diff --git a/.gn b/.gn index 0042ecbb..c780bc3 100644 --- a/.gn +++ b/.gn
@@ -20,6 +20,13 @@ # being built as part of Chrome vs. being built standalone. In this case, the # Chrome defaults should go here. There should be no overrides here for # values declared in the main Chrome repository. +# +# Important note for defining defaults: This file is executed before the +# BUILDCONFIG.gn file. That file sets up the global variables like "is_ios". +# This means that the default_args can not depend on the platform, +# architecture, or other build parameters. If you really need that, the other +# repo should define a flag that toggles on a behavior that implements the +# additional logic required by Chrome to set the variables. default_args = { v8_extra_library_files = [ # Dependencies used by the extra libraries. Putting them here causes them
diff --git a/BUILD.gn b/BUILD.gn index 7357321..613a340 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -383,10 +383,6 @@ deps += [ "//tools/xdisplaycheck" ] } - if (v8_use_external_startup_data) { - deps += [ "//gin:gin_v8_snapshot_fingerprint" ] - } - if (is_win) { deps += [ "//chrome/installer/gcapi", @@ -727,7 +723,6 @@ if (!is_ios) { deps += [ "//media/mojo:media_mojo_unittests", - "//mojo/common:mojo_common_perftests", "//services:service_unittests", ] }
diff --git a/DEPS b/DEPS index bbc9f82..86d7f0e 100644 --- a/DEPS +++ b/DEPS
@@ -40,11 +40,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'fd197d503493a1a35bb0da36ac22b18da379f940', + 'skia_revision': '77a7a1b57c16c97f056c1e50c03bdc954947778c', # 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': '9e240df9bb8454f5526f22db88bfcbe96e1632c8', + 'v8_revision': '88cea110a5d3182c65c680f702b5c24005423de8', # 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. @@ -64,7 +64,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '10def51edb8758632be9b24476459b0ab6f23c51', + 'pdfium_revision': '071d78690a4e2becffaeeb32fe210ee58ab3e532', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -96,7 +96,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': 'df67b479111472de101150fa01307279df03f24f', + 'catapult_revision': 'f20052d2acdba42cef9fb6e300d573dbcb2898b1', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -124,7 +124,7 @@ deps = { 'src/breakpad/src': - Var('chromium_git') + '/breakpad/breakpad/src.git' + '@' + '5c09282c5becdc7b8b3daaff950cdfcd45b615b3', + Var('chromium_git') + '/breakpad/breakpad/src.git' + '@' + '37070c5e680f3356f7b14d239518a104edbc2c97', 'src/buildtools': Var('chromium_git') + '/chromium/buildtools.git' + '@' + Var('buildtools_revision'), @@ -205,7 +205,7 @@ Var('chromium_git') + '/webm/libvpx.git' + '@' + '164db8278f68a5ab376500ed6aad99ef7da3e9b0', 'src/third_party/ffmpeg': - Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'bc2eb1987e956f5d2747e8c9c61ac346a2c91c92', + Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '239c9f9e275486c051f3313efb6725968bb9a004', 'src/third_party/usrsctp/usrsctplib': Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + '8679f2b0bf063ac894dc473debefd61dbbebf622', @@ -232,7 +232,7 @@ Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067', 'src/third_party/webrtc': - Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'a0add70a308a6fba9a8b404438c49ae75b40c309', # commit position 16440 + Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '6c1149b5aca93820664c5963180170e455220e8e', # commit position 16460 'src/third_party/openmax_dl': Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' + Var('openmax_dl_revision'),
diff --git a/WATCHLISTS b/WATCHLISTS index 3ed1b596..ddac364b 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -907,6 +907,9 @@ 'styleguide': { 'filepath': '^styleguide/', }, + 'subresource_filter': { + 'filepath': 'subresource_filter|SubresourceFilter', + }, 'supervised_users': { 'filepath': 'chrome/browser/.*managed_mode'\ '|chrome/browser/.*managed_user'\ @@ -1033,6 +1036,14 @@ '|ui/base/native_theme/resources/'\ '|chrome/app/theme/' }, + 'ui_strings': { + 'filepath': 'chrome/app/generated_resources.grd'\ + '|chrome/app/google_chrome_strings.grd'\ + '|chrome/android/java/strings/android_chrome_strings.grd'\ + '|chrome/app/settings_strings.grdp'\ + '|ios/chrome/app/strings/ios(_.+)*_strings.grd'\ + '|ui/strings/ui_strings.grd', + }, 'valgrind': { 'filepath': 'valgrind', }, @@ -2039,6 +2050,7 @@ 'styleguide': ['danakj+watch@chromium.org', 'jbroman+cpp@chromium.org', 'vmpstr+watch@chromium.org'], + 'subresource_filter': ['subresource-filter-reviews@chromium.org'], 'supervised_users': ['pam+watch@chromium.org'], 'swreporter': ['alito+watch@chromium.org', 'ftirelo+watch@chromium.org', @@ -2078,6 +2090,7 @@ 'ui_compositor': ['cc-bugs@chromium.org'], 'ui_display_win': ['robliao+watch@chromium.org'], 'ui_resources': ['oshima+watch@chromium.org'], + 'ui_strings': ['srahim+watch@chromium.org'], 'valgrind': ['bruening+watch@chromium.org', 'glider+watch@chromium.org'], 'version_assembly': ['caitkp+watch@chromium.org',
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn index 0e7bb13f..2d3b3cf 100644 --- a/android_webview/BUILD.gn +++ b/android_webview/BUILD.gn
@@ -757,6 +757,14 @@ ] } +android_library("android_webview_commandline_java") { + java_files = [ "java/src/org/chromium/android_webview/command_line/CommandLineUtil.java" ] + + deps = [ + "//base:base_java", + ] +} + # Keep crash services separate from other WebView code to keep their deps clean # (and make them easy to move). android_library("android_webview_crash_services_java") { @@ -767,6 +775,8 @@ "java/src/org/chromium/android_webview/crash/MinidumpUploadJobService.java", ] deps = [ + ":android_webview_commandline_java", + ":android_webview_platform_services_java", "//base:base_java", "//components/minidump_uploader:minidump_uploader_java", ]
diff --git a/android_webview/browser/renderer_host/aw_render_view_host_ext.cc b/android_webview/browser/renderer_host/aw_render_view_host_ext.cc index f222880..5ea6464 100644 --- a/android_webview/browser/renderer_host/aw_render_view_host_ext.cc +++ b/android_webview/browser/renderer_host/aw_render_view_host_ext.cc
@@ -13,12 +13,12 @@ #include "base/logging.h" #include "components/web_restrictions/browser/web_restrictions_mojo_implementation.h" #include "content/public/browser/android/content_view_core.h" +#include "content/public/browser/navigation_handle.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/user_metrics.h" #include "content/public/browser/web_contents.h" -#include "content/public/common/frame_navigate_params.h" #include "services/service_manager/public/cpp/interface_registry.h" namespace android_webview { @@ -152,14 +152,12 @@ AwBrowserContext::GetDefault()->GetWebRestrictionProvider())); } -void AwRenderViewHostExt::DidNavigateAnyFrame( - content::RenderFrameHost* render_frame_host, - const content::LoadCommittedDetails& details, - const content::FrameNavigateParams& params) { +void AwRenderViewHostExt::DidFinishNavigation( + content::NavigationHandle* navigation_handle) { DCHECK(CalledOnValidThread()); AwBrowserContext::FromWebContents(web_contents()) - ->AddVisitedURLs(params.redirects); + ->AddVisitedURLs(navigation_handle->GetRedirectChain()); } void AwRenderViewHostExt::OnPageScaleFactorChanged(float page_scale_factor) {
diff --git a/android_webview/browser/renderer_host/aw_render_view_host_ext.h b/android_webview/browser/renderer_host/aw_render_view_host_ext.h index c6bc1a1..9c6f604 100644 --- a/android_webview/browser/renderer_host/aw_render_view_host_ext.h +++ b/android_webview/browser/renderer_host/aw_render_view_host_ext.h
@@ -16,11 +16,6 @@ #include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size_f.h" -namespace content { -struct FrameNavigateParams; -struct LoadCommittedDetails; -} // namespace content - namespace android_webview { class AwRenderViewHostExtClient { @@ -87,9 +82,8 @@ void RenderViewHostChanged(content::RenderViewHost* old_host, content::RenderViewHost* new_host) override; void RenderFrameCreated(content::RenderFrameHost* frame_host) override; - void DidNavigateAnyFrame(content::RenderFrameHost* render_frame_host, - const content::LoadCommittedDetails& details, - const content::FrameNavigateParams& params) override; + void DidFinishNavigation( + content::NavigationHandle* navigation_handle) override; void OnPageScaleFactorChanged(float page_scale_factor) override; bool OnMessageReceived(const IPC::Message& message, content::RenderFrameHost* render_frame_host) override;
diff --git a/android_webview/glue/glue.gni b/android_webview/glue/glue.gni index c85dcd6..7da54cf 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_commandline_java", "//android_webview:android_webview_platform_services_java", "//base:base_java", "//content/public/android:content_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 b8b3bf0..22db843 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
@@ -16,7 +16,6 @@ import android.os.Build; import android.os.Looper; import android.os.Process; -import android.os.StrictMode; import android.os.UserManager; import android.provider.Settings; import android.util.Log; @@ -49,6 +48,7 @@ import org.chromium.android_webview.HttpAuthDatabase; import org.chromium.android_webview.PlatformServiceBridge; import org.chromium.android_webview.ResourcesContextWrapperFactory; +import org.chromium.android_webview.command_line.CommandLineUtil; import org.chromium.base.BuildConfig; import org.chromium.base.BuildInfo; import org.chromium.base.CommandLine; @@ -59,7 +59,6 @@ import org.chromium.base.PathUtils; import org.chromium.base.ThreadUtils; import org.chromium.base.TraceEvent; -import org.chromium.base.annotations.SuppressFBWarnings; import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.library_loader.LibraryProcessType; import org.chromium.base.library_loader.NativeLibraries; @@ -85,11 +84,7 @@ private static final String CHROMIUM_PREFS_NAME = "WebViewChromiumPrefs"; private static final String VERSION_CODE_PREF = "lastVersionCodeUsed"; - private static final String COMMAND_LINE_FILE = "/data/local/tmp/webview-command-line"; private static final String HTTP_AUTH_DATABASE_FILE = "http_auth.db"; - // same switch as kEnableCrashReporterForTesting in //base/base_switches.h - public static final String CRASH_UPLOADS_ENABLED_FOR_TESTING_SWITCH = - "enable-crash-reporter-for-testing"; private class WebViewChromiumRunQueue { public WebViewChromiumRunQueue() { @@ -209,7 +204,6 @@ initialize(delegate); } - @SuppressFBWarnings("DMI_HARDCODED_ABSOLUTE_FILENAME") private void initialize(WebViewDelegate webViewDelegate) { mWebViewDelegate = webViewDelegate; Context ctx = mWebViewDelegate.getApplication().getApplicationContext(); @@ -227,14 +221,7 @@ // WebView needs to make sure to always use the wrapped application context. ContextUtils.initApplicationContext(ResourcesContextWrapperFactory.get(ctx)); - if (isBuildDebuggable()) { - // Suppress the StrictMode violation as this codepath is only hit on debuggable builds. - StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); - CommandLine.initFromFile(COMMAND_LINE_FILE); - StrictMode.setThreadPolicy(oldPolicy); - } else { - CommandLine.init(null); - } + CommandLineUtil.initCommandLine(); boolean multiProcess = false; if (BuildInfo.isAtLeastO()) { @@ -290,10 +277,6 @@ } } - private static boolean isBuildDebuggable() { - return !Build.TYPE.equals("user"); - } - /** * Both versionCodes should be from a WebView provider package implemented by Chromium. * VersionCodes from other kinds of packages won't make any sense in this method. @@ -433,7 +416,7 @@ AwBrowserProcess.start(); final boolean enableMinidumpUploadingForTesting = CommandLine.getInstance().hasSwitch( - CRASH_UPLOADS_ENABLED_FOR_TESTING_SWITCH); + CommandLineUtil.CRASH_UPLOADS_ENABLED_FOR_TESTING_SWITCH); if (enableMinidumpUploadingForTesting) { AwBrowserProcess.handleMinidumps(webViewPackageName, true /* enabled */); } @@ -451,7 +434,7 @@ } }); - if (isBuildDebuggable()) { + if (CommandLineUtil.isBuildDebuggable()) { setWebContentsDebuggingEnabled(true); } @@ -547,7 +530,7 @@ @Override public void setWebContentsDebuggingEnabled(boolean enable) { // Web Contents debugging is always enabled on debug builds. - if (!isBuildDebuggable()) { + if (!CommandLineUtil.isBuildDebuggable()) { WebViewChromiumFactoryProvider.this.setWebContentsDebuggingEnabled( enable); }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java index 6ccba0af..83b9150 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -3004,8 +3004,10 @@ @Override public void extractSmartClipData(int x, int y, int width, int height) { + float dpi = mContentViewCore.getRenderCoordinates().getDeviceScaleFactor(); if (!isDestroyedOrNoOperation(WARN)) { - mContentViewCore.extractSmartClipData(x, y, width, height); + mWebContents.requestSmartClipExtract( + (int) (x / dpi), (int) (y / dpi), (int) (width / dpi), (int) (height / dpi)); } } @@ -3013,28 +3015,7 @@ public void setSmartClipResultHandler(final Handler resultHandler) { if (isDestroyedOrNoOperation(WARN)) return; - if (resultHandler == null) { - mContentViewCore.setSmartClipDataListener(null); - return; - } - mContentViewCore.setSmartClipDataListener(new ContentViewCore.SmartClipDataListener() { - @Override - public void onSmartClipDataExtracted(String text, String html, Rect clipRect) { - Bundle bundle = new Bundle(); - bundle.putString("url", mContentViewCore.getWebContents().getVisibleUrl()); - bundle.putString("title", mContentViewCore.getWebContents().getTitle()); - bundle.putParcelable("rect", clipRect); - bundle.putString("text", text); - bundle.putString("html", html); - try { - Message msg = Message.obtain(resultHandler, 0); - msg.setData(bundle); - msg.sendToTarget(); - } catch (Exception e) { - Log.e(TAG, "Error calling handler for smart clip data: ", e); - } - } - }); + mWebContents.setSmartClipResultHandler(resultHandler); } protected void insertVisualStateCallbackIfNotDestroyed(
diff --git a/android_webview/java/src/org/chromium/android_webview/command_line/CommandLineUtil.java b/android_webview/java/src/org/chromium/android_webview/command_line/CommandLineUtil.java new file mode 100644 index 0000000..e05c309 --- /dev/null +++ b/android_webview/java/src/org/chromium/android_webview/command_line/CommandLineUtil.java
@@ -0,0 +1,50 @@ +// 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. + +package org.chromium.android_webview.command_line; + +import android.os.Build; +import android.os.StrictMode; + +import org.chromium.base.CommandLine; +import org.chromium.base.annotations.SuppressFBWarnings; + +/** + * Utility class for WebView's CommandLine - this is compiled into a separate target that can be + * reached from WebView's separate minidump-uploading Services. + */ +public class CommandLineUtil { + private CommandLineUtil() {} + + public static final String WEBVIEW_COMMAND_LINE_FILE = "/data/local/tmp/webview-command-line"; + + // same switch as kEnableCrashReporterForTesting in //base/base_switches.h + public static final String CRASH_UPLOADS_ENABLED_FOR_TESTING_SWITCH = + "enable-crash-reporter-for-testing"; + + public static boolean isBuildDebuggable() { + return !Build.TYPE.equals("user"); + } + + /** + * Initialize the CommandLine for WebView - this should be initialized on the same thread where + * we subsequently access CommandLine. + */ + @SuppressFBWarnings("DMI_HARDCODED_ABSOLUTE_FILENAME") + public static void initCommandLine() { + if (isBuildDebuggable()) { + // Suppress the StrictMode violation as this codepath is only hit on debuggable builds. + StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); + CommandLine.initFromFile(CommandLineUtil.WEBVIEW_COMMAND_LINE_FILE); + StrictMode.setThreadPolicy(oldPolicy); + } else { + CommandLine.init(null); + } + } + + public static void initCommandLineIfNotInitialized() { + if (CommandLine.isInitialized()) return; + initCommandLine(); + } +}
diff --git a/android_webview/java/src/org/chromium/android_webview/crash/MinidumpUploaderImpl.java b/android_webview/java/src/org/chromium/android_webview/crash/MinidumpUploaderImpl.java index b21302d..e47cd268 100644 --- a/android_webview/java/src/org/chromium/android_webview/crash/MinidumpUploaderImpl.java +++ b/android_webview/java/src/org/chromium/android_webview/crash/MinidumpUploaderImpl.java
@@ -7,8 +7,13 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; +import android.webkit.ValueCallback; +import org.chromium.android_webview.PlatformServiceBridge; +import org.chromium.android_webview.command_line.CommandLineUtil; +import org.chromium.base.CommandLine; import org.chromium.base.Log; +import org.chromium.base.ThreadUtils; import org.chromium.base.VisibleForTesting; import org.chromium.components.minidump_uploader.CrashFileManager; import org.chromium.components.minidump_uploader.MinidumpUploadCallable; @@ -26,14 +31,15 @@ */ public class MinidumpUploaderImpl implements MinidumpUploader { private static final String TAG = "MinidumpUploaderImpl"; + private Context mContext; private Thread mWorkerThread; private final ConnectivityManager mConnectivityManager; private final CrashFileManager mFileManager; - private Object mCancelLock = new Object(); private boolean mCancelUpload = false; private final boolean mCleanOutMinidumps; + private boolean mPermittedByUser = false; @VisibleForTesting public static final int MAX_UPLOAD_TRIES_ALLOWED = 3; @@ -43,24 +49,21 @@ * more minidumps. */ private void setCancelUpload(boolean cancel) { - synchronized (mCancelLock) { - mCancelUpload = cancel; - } + mCancelUpload = cancel; } /** * Check whether the current job has been canceled. */ private boolean getCancelUpload() { - synchronized (mCancelLock) { - return mCancelUpload; - } + return mCancelUpload; } @VisibleForTesting public MinidumpUploaderImpl(Context context, boolean cleanOutMinidumps) { mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + mContext = context; File webviewCrashDir = CrashReceiverService.createWebViewCrashDir(context); mFileManager = new CrashFileManager(webviewCrashDir); if (!mFileManager.ensureCrashDirExists()) { @@ -79,7 +82,17 @@ minidumpFile, logfile, createWebViewCrashReportingManager()); } - private final CrashReportingPermissionManager createWebViewCrashReportingManager() { + /** + * Utility method to allow us to test the logic of this class by injecting + * a test-PlatformServiceBridge. + */ + @VisibleForTesting + public PlatformServiceBridge createPlatformServiceBridge() { + return PlatformServiceBridge.getInstance(mContext); + } + + @VisibleForTesting + protected CrashReportingPermissionManager createWebViewCrashReportingManager() { return new CrashReportingPermissionManager() { @Override public boolean isClientInMetricsSample() { @@ -112,15 +125,15 @@ } @Override public boolean isUsageAndCrashReportingPermittedByUser() { - // We ensure we have user permission before copying minidumps to the directory used - // by this process - so always return true here. - return true; + return mPermittedByUser; } @Override public boolean isUploadEnabledForTests() { - // We are already checking whether this feature is enabled for manual testing before - // copying minidumps. - return false; + // Note that CommandLine/CommandLineUtil are not thread safe (so only use them from + // one thread!). + CommandLineUtil.initCommandLineIfNotInitialized(); + return CommandLine.getInstance().hasSwitch( + CommandLineUtil.CRASH_UPLOADS_ENABLED_FOR_TESTING_SWITCH); } }; } @@ -174,12 +187,27 @@ @Override public void uploadAllMinidumps( final MinidumpUploader.UploadsFinishedCallback uploadsFinishedCallback) { + // This call should happen on the main thread + ThreadUtils.assertOnUiThread(); if (mWorkerThread != null) { throw new RuntimeException("Only one upload-job should be active at a time"); } mWorkerThread = new Thread(new UploadRunnable(uploadsFinishedCallback), "mWorkerThread"); setCancelUpload(false); - mWorkerThread.start(); + + createPlatformServiceBridge().queryMetricsSetting(new ValueCallback<Boolean>() { + public void onReceiveValue(Boolean enabled) { + // This callback should be received on the main thread (e.g. mWorkerThread + // is not thread-safe). + ThreadUtils.assertOnUiThread(); + + mPermittedByUser = enabled; + // Our job might have been cancelled by now - make sure we honour this. + if (!getCancelUpload()) { + mWorkerThread.start(); + } + } + }); } /**
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientOnRenderProcessGoneTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientOnRenderProcessGoneTest.java index fc5e1504..a819b6f3 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientOnRenderProcessGoneTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientOnRenderProcessGoneTest.java
@@ -15,10 +15,13 @@ import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.parameter.ParameterizedTest; +import java.util.concurrent.TimeUnit; + /** * Tests for AwContentsClient.onRenderProcessGone callback. */ public class AwContentsClientOnRenderProcessGoneTest extends AwTestBase { + private static final String TAG = "AwRendererGone"; private static class GetRenderProcessGoneHelper extends CallbackHelper { private AwRenderProcessGoneDetail mDetail; @@ -65,8 +68,8 @@ GetRenderProcessGoneHelper helper = contentsClient.getGetRenderProcessGoneHelper(); loadUrlAsync(awContents, "chrome://crash"); int callCount = helper.getCallCount(); - helper.waitForCallback(callCount); - + helper.waitForCallback(callCount, 1, CallbackHelper.WAIT_TIMEOUT_SECONDS * 5, + TimeUnit.SECONDS); assertEquals(callCount + 1, helper.getCallCount()); assertTrue(helper.getAwRenderProcessGoneDetail().didCrash()); assertEquals(RendererPriority.HIGH,
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/crash/MinidumpUploaderTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/crash/MinidumpUploaderTest.java index 0f39c4c..1ff8dc96 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/crash/MinidumpUploaderTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/crash/MinidumpUploaderTest.java
@@ -9,11 +9,14 @@ import android.content.Context; import android.os.ParcelFileDescriptor; import android.test.suitebuilder.annotation.MediumTest; +import android.webkit.ValueCallback; +import org.chromium.android_webview.PlatformServiceBridge; import org.chromium.android_webview.crash.CrashReceiverService; import org.chromium.android_webview.crash.MinidumpUploader; import org.chromium.android_webview.crash.MinidumpUploaderImpl; import org.chromium.base.FileUtils; +import org.chromium.base.ThreadUtils; import org.chromium.components.minidump_uploader.CrashFileManager; import org.chromium.components.minidump_uploader.CrashTestCase; import org.chromium.components.minidump_uploader.MinidumpUploadCallable; @@ -47,6 +50,51 @@ return CrashReceiverService.createWebViewCrashDir(getInstrumentation().getTargetContext()); } + private static class TestPlatformServiceBridge extends PlatformServiceBridge { + boolean mCanUseGms; + boolean mUserPermitted; + + public TestPlatformServiceBridge(boolean canUseGms, boolean userPermitted) { + mCanUseGms = canUseGms; + mUserPermitted = userPermitted; + } + + @Override + public boolean canUseGms() { + return mCanUseGms; + } + + @Override + public void queryMetricsSetting(ValueCallback<Boolean> callback) { + ThreadUtils.assertOnUiThread(); + callback.onReceiveValue(mUserPermitted); + } + } + + private static class TestMinidumpUploaderImpl extends MinidumpUploaderImpl { + private CrashReportingPermissionManager mPermissionManager; + + TestMinidumpUploaderImpl(Context context, CrashReportingPermissionManager permissionManager, + boolean cleanOutMinidumps) { + super(context, cleanOutMinidumps); + mPermissionManager = permissionManager; + } + + @Override + public MinidumpUploadCallable createMinidumpUploadCallable( + File minidumpFile, File logfile) { + return new MinidumpUploadCallable(minidumpFile, logfile, + new MinidumpUploadCallableTest.TestHttpURLConnectionFactory(), + mPermissionManager); + } + + @Override + public PlatformServiceBridge createPlatformServiceBridge() { + return new TestPlatformServiceBridge(true /* canUseGms */, + mPermissionManager.isUsageAndCrashReportingPermittedByUser()); + } + } + /** * Test to ensure the minidump uploading mechanism behaves as expected when we fail to upload * minidumps. @@ -64,15 +112,9 @@ mIsEnabledForTests = false; } }; - MinidumpUploader minidumpUploader = new MinidumpUploaderImpl( - getInstrumentation().getTargetContext(), false /* cleanOutMinidumps */) { - @Override - public MinidumpUploadCallable createMinidumpUploadCallable( - File minidumpFile, File logfile) { - return new MinidumpUploadCallable(minidumpFile, logfile, - new MinidumpUploadCallableTest.TestHttpURLConnectionFactory(), permManager); - } - }; + MinidumpUploader minidumpUploader = + new TestMinidumpUploaderImpl(getInstrumentation().getTargetContext(), permManager, + false /* cleanOutMinidumps */); File firstFile = createMinidumpFileInCrashDir("1_abc.dmp0"); File secondFile = createMinidumpFileInCrashDir("12_abc.dmp0"); @@ -98,16 +140,31 @@ assertTrue(maxTriesFile.exists()); } + /** + * Utility method for running {@param minidumpUploader}.uploadAllMinidumps on the UI thread to + * avoid breaking any assertions about running on the UI thread. + */ + private static void uploadAllMinidumpsOnUiThread(final MinidumpUploader minidumpUploader, + final MinidumpUploader.UploadsFinishedCallback uploadsFinishedCallback) { + ThreadUtils.runOnUiThread(new Runnable() { + @Override + public void run() { + minidumpUploader.uploadAllMinidumps(uploadsFinishedCallback); + } + }); + } + private static void uploadMinidumpsSync( MinidumpUploader minidumpUploader, final boolean expectReschedule) { final CountDownLatch uploadsFinishedLatch = new CountDownLatch(1); - minidumpUploader.uploadAllMinidumps(new MinidumpUploader.UploadsFinishedCallback() { - @Override - public void uploadsFinished(boolean reschedule) { - assertEquals(expectReschedule, reschedule); - uploadsFinishedLatch.countDown(); - } - }); + uploadAllMinidumpsOnUiThread( + minidumpUploader, new MinidumpUploader.UploadsFinishedCallback() { + @Override + public void uploadsFinished(boolean reschedule) { + assertEquals(expectReschedule, reschedule); + uploadsFinishedLatch.countDown(); + } + }); try { assertTrue(uploadsFinishedLatch.await( scaleTimeout(TIME_OUT_MILLIS), TimeUnit.MILLISECONDS)); @@ -131,15 +188,9 @@ new MockCrashReportingPermissionManager() { { mIsEnabledForTests = true; } }; - MinidumpUploader minidumpUploader = new MinidumpUploaderImpl( - getInstrumentation().getTargetContext(), false /* cleanOutMinidumps */) { - @Override - public MinidumpUploadCallable createMinidumpUploadCallable( - File minidumpFile, File logfile) { - return new MinidumpUploadCallable(minidumpFile, logfile, - new MinidumpUploadCallableTest.TestHttpURLConnectionFactory(), permManager); - } - }; + MinidumpUploader minidumpUploader = + new TestMinidumpUploaderImpl(getInstrumentation().getTargetContext(), permManager, + false /* cleanOutMinidumps */); File firstFile = createMinidumpFileInCrashDir("1_abc.dmp0"); File secondFile = createMinidumpFileInCrashDir("12_abcd.dmp0"); @@ -160,8 +211,8 @@ MinidumpUploadCallable createCallable(File minidumpFile, File logfile); } - private static MinidumpUploaderImpl createCallableListMinidumpUploader( - Context context, final List<MinidumpUploadCallableCreator> callables) { + private static MinidumpUploaderImpl createCallableListMinidumpUploader(Context context, + final List<MinidumpUploadCallableCreator> callables, final boolean userPermitted) { return new MinidumpUploaderImpl(context, false /* cleanOutMinidumps */) { private int mIndex = 0; @@ -173,6 +224,10 @@ } return callables.get(mIndex++).createCallable(minidumpFile, logfile); } + @Override + public PlatformServiceBridge createPlatformServiceBridge() { + return new TestPlatformServiceBridge(true /* canUseGms*/, userPermitted); + } }; } @@ -197,8 +252,9 @@ new MinidumpUploadCallableTest.TestHttpURLConnectionFactory(), permManager); } }); - MinidumpUploader minidumpUploader = createCallableListMinidumpUploader( - getInstrumentation().getTargetContext(), callables); + MinidumpUploader minidumpUploader = + createCallableListMinidumpUploader(getInstrumentation().getTargetContext(), + callables, permManager.isUsageAndCrashReportingPermittedByUser()); File firstFile = createMinidumpFileInCrashDir("firstFile.dmp0"); File secondFile = createMinidumpFileInCrashDir("secondFile.dmp0"); @@ -276,18 +332,25 @@ return new MinidumpUploadCallable( minidumpFile, logfile, new StallingHttpUrlConnectionFactory(), permManager); } + @Override + public PlatformServiceBridge createPlatformServiceBridge() { + return new TestPlatformServiceBridge( + true /* canUseGms*/, permManager.isUsageAndCrashReportingPermittedByUser()); + } }; File firstFile = createMinidumpFileInCrashDir("123_abc.dmp0"); File nonExpectedFirstUploadFile = new File(mCrashDir, firstFile.getName() + ".up"); File nonExpectedFirstRetryFile = new File(mCrashDir, firstFile.getName() + ".try1"); - minidumpUploader.uploadAllMinidumps(new MinidumpUploader.UploadsFinishedCallback() { - @Override - public void uploadsFinished(boolean reschedule) { - fail("This method shouldn't be called when we interrupt uploads."); - } - }); + // This is run on the UI thread to avoid failing any assertOnUiThread assertions. + uploadAllMinidumpsOnUiThread( + minidumpUploader, new MinidumpUploader.UploadsFinishedCallback() { + @Override + public void uploadsFinished(boolean reschedule) { + fail("This method shouldn't be called when we interrupt uploads."); + } + }); minidumpUploader.cancelUploads(); assertTrue(firstFile.exists()); @@ -326,6 +389,91 @@ assertEquals(0, webviewTmpDir.listFiles().length); } + /** + * Ensure that when PlatformServiceBridge returns true we do upload minidumps. + */ + @MediumTest + public void testPlatformServicesBridgeIsUsedUserConsent() throws IOException { + testPlatformServicesBridgeIsUsed(true); + } + + /** + * Ensure that when PlatformServiceBridge returns false we do not upload minidumps. + */ + @MediumTest + public void testPlatformServicesBridgeIsUsedNoUserConsent() throws IOException { + testPlatformServicesBridgeIsUsed(false); + } + + /** + * MinidumpUploaderImpl sub-class that uses MinidumpUploaderImpl's implementation of + * CrashReportingPermissionManager.isUsageAndCrashReportingPermittedByUser(). + */ + private static class WebViewUserConsentMinidumpUploaderImpl extends MinidumpUploaderImpl { + boolean mUserConsent; + WebViewUserConsentMinidumpUploaderImpl( + Context context, boolean cleanOutMinidumps, boolean userConsent) { + super(context, cleanOutMinidumps); + mUserConsent = userConsent; + } + @Override + public PlatformServiceBridge createPlatformServiceBridge() { + return new TestPlatformServiceBridge(true /* canUseGms */, mUserConsent); + } + @Override + public MinidumpUploadCallable createMinidumpUploadCallable( + File minidumpFile, File logfile) { + return new MinidumpUploadCallable(minidumpFile, logfile, + new MinidumpUploadCallableTest.TestHttpURLConnectionFactory(), + createWebViewCrashReportingManager()); + } + @Override + protected CrashReportingPermissionManager createWebViewCrashReportingManager() { + final CrashReportingPermissionManager realPermissionManager = + super.createWebViewCrashReportingManager(); + return new MockCrashReportingPermissionManager() { + { + // This setup ensures we depend on + // isUsageAndCrashReportingPermittedByUser(). + mIsInSample = true; + mIsPermitted = true; + mIsCommandLineDisabled = false; + mIsNetworkAvailable = true; + mIsEnabledForTests = false; + } + @Override + public boolean isUsageAndCrashReportingPermittedByUser() { + // Ensure that we use the real implementation of + // isUsageAndCrashReportingPermittedByUser. + boolean userPermitted = + realPermissionManager.isUsageAndCrashReportingPermittedByUser(); + assertEquals(mUserConsent, userPermitted); + return userPermitted; + } + }; + } + } + + private void testPlatformServicesBridgeIsUsed(final boolean userConsent) throws IOException { + MinidumpUploader minidumpUploader = + new WebViewUserConsentMinidumpUploaderImpl(getInstrumentation().getTargetContext(), + false /* cleanOutMinidumps */, userConsent); + + File firstFile = createMinidumpFileInCrashDir("1_abc.dmp0"); + File secondFile = createMinidumpFileInCrashDir("12_abcd.dmp0"); + File expectedFirstFile = new File( + mCrashDir, firstFile.getName().replace(".dmp", userConsent ? ".up" : ".skipped")); + File expectedSecondFile = new File( + mCrashDir, secondFile.getName().replace(".dmp", userConsent ? ".up" : ".skipped")); + + uploadMinidumpsSync(minidumpUploader, false /* expectReschedule */); + + assertFalse(firstFile.exists()); + assertTrue(expectedFirstFile.exists()); + assertFalse(secondFile.exists()); + assertTrue(expectedSecondFile.exists()); + } + private static String readEntireFile(File file) throws IOException { FileInputStream fileInputStream = new FileInputStream(file); try { @@ -450,15 +598,9 @@ new MockCrashReportingPermissionManager() { { mIsEnabledForTests = true; } }; - MinidumpUploader minidumpUploader = new MinidumpUploaderImpl( - getInstrumentation().getTargetContext(), false /* cleanOutMinidumps */) { - @Override - public MinidumpUploadCallable createMinidumpUploadCallable( - File minidumpFile, File logfile) { - return new MinidumpUploadCallable(minidumpFile, logfile, - new MinidumpUploadCallableTest.TestHttpURLConnectionFactory(), permManager); - } - }; + MinidumpUploader minidumpUploader = + new TestMinidumpUploaderImpl(getInstrumentation().getTargetContext(), permManager, + false /* cleanOutMinidumps */); uploadMinidumpsSync(minidumpUploader, false /* expectReschedule */); // Ensure there are no minidumps left to upload.
diff --git a/android_webview/lib/main/webview_jni_onload.cc b/android_webview/lib/main/webview_jni_onload.cc index eb8d10d5..1edce09 100644 --- a/android_webview/lib/main/webview_jni_onload.cc +++ b/android_webview/lib/main/webview_jni_onload.cc
@@ -26,7 +26,12 @@ web_contents_delegate_android::RegisterWebContentsDelegateAndroidJni }, }; -bool RegisterJNI(JNIEnv* env) { +} // namespace + +bool OnJNIOnLoadRegisterJNI(JNIEnv* env) { + if (!content::android::OnJNIOnLoadRegisterJNI(env)) + return false; + // Register JNI for components we depend on. if (!RegisterNativeMethods( env, @@ -38,7 +43,10 @@ return true; } -bool Init() { +bool OnJNIOnLoadInit() { + if (!content::android::OnJNIOnLoadInit()) + return false; + base::android::SetVersionNumber(PRODUCT_VERSION); content::SetContentMainDelegate(new android_webview::AwMainDelegate()); @@ -49,18 +57,4 @@ return true; } -} // namespace - -bool OnJNIOnLoadRegisterJNI(JavaVM* vm) { - std::vector<base::android::RegisterCallback> register_callbacks; - register_callbacks.push_back(base::Bind(&RegisterJNI)); - return content::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks); -} - -bool OnJNIOnLoadInit() { - std::vector<base::android::InitCallback> init_callbacks; - init_callbacks.push_back(base::Bind(&Init)); - return content::android::OnJNIOnLoadInit(init_callbacks); -} - } // android_webview
diff --git a/android_webview/lib/main/webview_jni_onload.h b/android_webview/lib/main/webview_jni_onload.h index 7621e0d..44d46a9 100644 --- a/android_webview/lib/main/webview_jni_onload.h +++ b/android_webview/lib/main/webview_jni_onload.h
@@ -11,7 +11,7 @@ // TODO(michaelbai): remove this once we no longer need to be able to run // webview with manual JNI registration -bool OnJNIOnLoadRegisterJNI(JavaVM* vm); +bool OnJNIOnLoadRegisterJNI(JNIEnv* env); bool OnJNIOnLoadInit();
diff --git a/android_webview/renderer/aw_render_thread_observer.cc b/android_webview/renderer/aw_render_thread_observer.cc index 9faf9f0..863cabea 100644 --- a/android_webview/renderer/aw_render_thread_observer.cc +++ b/android_webview/renderer/aw_render_thread_observer.cc
@@ -6,7 +6,7 @@ #include "android_webview/common/render_view_messages.h" #include "ipc/ipc_message_macros.h" -#include "third_party/WebKit/public/web/WebCache.h" +#include "third_party/WebKit/public/platform/WebCache.h" #include "third_party/WebKit/public/web/WebNetworkStateNotifier.h" namespace android_webview {
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn index 7da7eab..e341ddf0 100644 --- a/android_webview/test/BUILD.gn +++ b/android_webview/test/BUILD.gn
@@ -103,6 +103,7 @@ deps = [ "//android_webview:android_webview_crash_services_java", "//android_webview:android_webview_java", + "//android_webview:android_webview_platform_services_java", "//base:base_java", "//base:base_java_test_support", "//components/minidump_uploader:minidump_uploader_java",
diff --git a/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt b/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt index 9c59a8d..73c8f33 100644 --- a/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt +++ b/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt
@@ -1,5 +1,5 @@ -# speech not enabled crbug.com/487255 -interface SpeechSynthesisEvent : Event # speech not enabled +# speech api not enabled in webview, crbug.com/487255 +interface SpeechSynthesisEvent : Event interface SpeechSynthesisUtterance : EventTarget interface webkitSpeechGrammar interface webkitSpeechGrammarList @@ -7,17 +7,17 @@ interface webkitSpeechRecognitionError : Event interface webkitSpeechRecognitionEvent : Event -# permissions api not enabled in webview crbug.com/490120 +# permissions api not enabled in webview, crbug.com/490120 interface PermissionStatus : EventTarget interface Permissions -# notifications api not enabled in webview crbug.com/434712 +# notifications api not enabled in webview, crbug.com/434712 interface Notification : EventTarget -# not yet supported in webview. +# not yet supported in webview and chrome on android in general, crbug.com/154571 interface SharedWorker : EventTarget -# push API not supported in webview +# push API not supported in webview, crbug.com/421921 interface PushManager interface PushSubscription interface PushSubscriptionOptions @@ -33,18 +33,21 @@ # remoteplayback api not supported in webview crbug.com/521319 interface RemotePlayback : EventTarget -# crbug.com/589500 +# Android does not support switching the audio output device, crbug.com/589500 +# Remote Playback API is not supported on Android WebView, crbug.com/521319 interface HTMLMediaElement : HTMLElement - getter sinkId - method setSinkId + getter sinkId # crbug.com/589500 + method setSinkId # crbug.com/589500 setter disableRemotePlayback # crbug.com/521319 getter disableRemotePlayback # crbug.com/521319 getter remote # crbug.com/521319 +# permissions API (crbug.com/490120), presentation API (crbug.com/521319) and +# custom scheme handlers (crbug.com/589502) not supported in webview interface Navigator getter permissions # crbug.com/490120 - method registerProtocolHandler # crbug.com/589502 getter presentation # crbug.com/521319 + method registerProtocolHandler # crbug.com/589502 method unregisterProtocolHandler # crbug.com/589502 # notifications not yet supported in webview, crbug.com/551446 @@ -53,33 +56,31 @@ method getNotifications method showNotification -# crbug.com/589504 +# File System API disabled in WebView, crbug.com/589504, crbug.com/589843, b/6930981 interface HTMLInputElement : HTMLElement getter webkitEntries -# crbug.com/671461 +# MediaDevices devicechange disabled on Android, crbug.com/671461 interface MediaDevices : EventTarget getter ondevicechange setter ondevicechange -# TODO(timvolodine): investigate in more detail [GLOBAL OBJECT] method openDatabase - attribute layoutTestController - attribute eventSender - method webkitRequestFileSystem - attribute testRunner - attribute internals - attribute accessibilityController - attribute textInputController + attribute layoutTestController # test only + attribute eventSender # test only + attribute testRunner # test only + attribute internals # test only + attribute accessibilityController # test only + attribute textInputController # test only attribute gin - attribute gamepadController - attribute GCController - getter speechSynthesis - attribute chrome # crbug.com/618471 - method gc - method webkitResolveLocalFileSystemURL + attribute gamepadController # test only + attribute GCController # test only + getter speechSynthesis # Speech API, crbug.com/487255 + attribute chrome # crbug.com/618471 + method gc # test only + method webkitRequestFileSystem # File System API, crbug.com/589843 + method webkitResolveLocalFileSystemURL # File System API, crbug.com/589843 # TODO(timvolodine): check screen orientation lock api # TODO(timvolodine): check notifications in service workers -# TODO(timvolodine): add File System API
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index f9856ebe3..5549cfe 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -151,6 +151,8 @@ "common/shelf/overflow_button.h", "common/shelf/shelf_alignment_menu.cc", "common/shelf/shelf_alignment_menu.h", + "common/shelf/shelf_application_menu_model.cc", + "common/shelf/shelf_application_menu_model.h", "common/shelf/shelf_background_animator.cc", "common/shelf/shelf_background_animator.h", "common/shelf/shelf_background_animator_observer.h", @@ -368,8 +370,6 @@ "common/system/tray/default_system_tray_delegate.h", "common/system/tray/fixed_sized_image_view.cc", "common/system/tray/fixed_sized_image_view.h", - "common/system/tray/fixed_sized_scroll_view.cc", - "common/system/tray/fixed_sized_scroll_view.h", "common/system/tray/hover_highlight_view.cc", "common/system/tray/hover_highlight_view.h", "common/system/tray/ime_info.cc", @@ -421,10 +421,6 @@ "common/system/tray/tray_popup_item_container.h", "common/system/tray/tray_popup_item_style.cc", "common/system/tray/tray_popup_item_style.h", - "common/system/tray/tray_popup_label_button.cc", - "common/system/tray/tray_popup_label_button.h", - "common/system/tray/tray_popup_label_button_border.cc", - "common/system/tray/tray_popup_label_button_border.h", "common/system/tray/tray_popup_utils.cc", "common/system/tray/tray_popup_utils.h", "common/system/tray/tray_utils.cc", @@ -1186,6 +1182,7 @@ "common/popup_message_unittest.cc", # TODO: convert to use AshTest http://crbug.com/654494. + "common/shelf/shelf_application_menu_model_unittest.cc", "common/shelf/shelf_background_animator_unittest.cc", "common/shelf/shelf_button_pressed_metric_tracker_unittest.cc", "common/shelf/shelf_locking_manager_unittest.cc",
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index 76c3e8a..e6e87ac 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -278,6 +278,12 @@ <message name="IDS_ASH_STATUS_TRAY_BLUETOOTH_DISCOVERING" desc="The label used in the tray popup to show bluetooth is discovering devices."> Scanning for devices... </message> + <message name="IDS_ASH_STATUS_TRAY_BLUETOOTH_PAIRED_DEVICES" desc="The sub-header label for paired devices in Bluetooth device list."> + Paired devices + </message> + <message name="IDS_ASH_STATUS_TRAY_BLUETOOTH_UNPAIRED_DEVICES" desc="The sub-header label for unpaired devices in Bluetooth device list."> + Unpaired devices + </message> <message name="IDS_ASH_STATUS_TRAY_UPDATE" desc="The label used in the tray popup to notify that the user should restart to get system updates."> Restart to update
diff --git a/ash/autoclick/common/autoclick_ring_handler.cc b/ash/autoclick/common/autoclick_ring_handler.cc index 1b4a3064..db7ba7e 100644 --- a/ash/autoclick/common/autoclick_ring_handler.cc +++ b/ash/autoclick/common/autoclick_ring_handler.cc
@@ -45,13 +45,13 @@ void PaintAutoclickRingCircle(gfx::Canvas* canvas, gfx::Point& center, int radius) { - cc::PaintFlags paint; - paint.setStyle(cc::PaintFlags::kStroke_Style); - paint.setStrokeWidth(2 * kAutoclickRingArcWidth); - paint.setColor(kAutoclickRingCircleColor); - paint.setAntiAlias(true); + cc::PaintFlags flags; + flags.setStyle(cc::PaintFlags::kStroke_Style); + flags.setStrokeWidth(2 * kAutoclickRingArcWidth); + flags.setColor(kAutoclickRingCircleColor); + flags.setAntiAlias(true); - canvas->DrawCircle(center, radius, paint); + canvas->DrawCircle(center, radius, flags); } void PaintAutoclickRingArc(gfx::Canvas* canvas, @@ -59,17 +59,17 @@ int radius, int start_angle, int end_angle) { - cc::PaintFlags paint; - paint.setStyle(cc::PaintFlags::kStroke_Style); - paint.setStrokeWidth(2 * kAutoclickRingArcWidth); - paint.setColor(kAutoclickRingArcColor); - paint.setAntiAlias(true); + cc::PaintFlags flags; + flags.setStyle(cc::PaintFlags::kStroke_Style); + flags.setStrokeWidth(2 * kAutoclickRingArcWidth); + flags.setColor(kAutoclickRingArcColor); + flags.setAntiAlias(true); SkPath arc_path; arc_path.addArc(SkRect::MakeXYWH(center.x() - radius, center.y() - radius, 2 * radius, 2 * radius), start_angle, end_angle - start_angle); - canvas->DrawPath(arc_path, paint); + canvas->DrawPath(arc_path, flags); } } // namespace
diff --git a/ash/common/accelerators/debug_commands.cc b/ash/common/accelerators/debug_commands.cc index d895a888..0848b30 100644 --- a/ash/common/accelerators/debug_commands.cc +++ b/ash/common/accelerators/debug_commands.cc
@@ -92,12 +92,12 @@ gfx::Size image_size(1366, 768); gfx::Canvas canvas(image_size, 1.0f, true); canvas.DrawColor(fill); - cc::PaintFlags paint; - paint.setColor(rect); - paint.setStrokeWidth(10); - paint.setStyle(cc::PaintFlags::kStroke_Style); - paint.setBlendMode(SkBlendMode::kSrcOver); - canvas.DrawRoundRect(gfx::Rect(image_size), 100, paint); + cc::PaintFlags flags; + flags.setColor(rect); + flags.setStrokeWidth(10); + flags.setStyle(cc::PaintFlags::kStroke_Style); + flags.setBlendMode(SkBlendMode::kSrcOver); + canvas.DrawRoundRect(gfx::Rect(image_size), 100, flags); return gfx::ImageSkia(canvas.ExtractImageRep()); }
diff --git a/ash/common/accelerators/exit_warning_handler.cc b/ash/common/accelerators/exit_warning_handler.cc index 370dfbb..9393425 100644 --- a/ash/common/accelerators/exit_warning_handler.cc +++ b/ash/common/accelerators/exit_warning_handler.cc
@@ -73,10 +73,10 @@ } void OnPaint(gfx::Canvas* canvas) override { - cc::PaintFlags paint; - paint.setStyle(cc::PaintFlags::kFill_Style); - paint.setColor(kWindowBackgroundColor); - canvas->DrawRoundRect(GetLocalBounds(), kWindowCornerRadius, paint); + cc::PaintFlags flags; + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setColor(kWindowBackgroundColor); + canvas->DrawRoundRect(GetLocalBounds(), kWindowCornerRadius, flags); views::WidgetDelegateView::OnPaint(canvas); }
diff --git a/ash/common/ash_switches.cc b/ash/common/ash_switches.cc index 3141b2c4..37ac6b3 100644 --- a/ash/common/ash_switches.cc +++ b/ash/common/ash_switches.cc
@@ -51,9 +51,6 @@ const char kAshEnableMagnifierKeyScroller[] = "ash-enable-magnifier-key-scroller"; -// Enables the palette next to the status area. -const char kAshEnablePalette[] = "ash-enable-palette"; - // Enables the palette on every display, instead of only the internal one. const char kAshEnablePaletteOnAllDisplays[] = "ash-enable-palette-on-all-displays"; @@ -68,6 +65,9 @@ // Enables mirrored screen. const char kAshEnableMirroredScreen[] = "ash-enable-mirrored-screen"; +// Enables the palette next to the status area. +const char kAshForceEnablePalette[] = "ash-force-enable-palette"; + // Hides notifications that are irrelevant to Chrome OS device factory testing, // such as battery level updates. const char kAshHideNotificationsForFactory[] =
diff --git a/ash/common/ash_switches.h b/ash/common/ash_switches.h index ee10c85..b7cc771 100644 --- a/ash/common/ash_switches.h +++ b/ash/common/ash_switches.h
@@ -25,12 +25,11 @@ ASH_EXPORT extern const char kAshDisableTouchExplorationMode[]; ASH_EXPORT extern const char kAshEnableFullscreenAppList[]; ASH_EXPORT extern const char kAshEnableMagnifierKeyScroller[]; -ASH_EXPORT extern const char kAshEnablePalette[]; ASH_EXPORT extern const char kAshEnablePaletteOnAllDisplays[]; ASH_EXPORT extern const char kAshEnableDockedWindows[]; ASH_EXPORT extern const char kAshEnableTouchView[]; ASH_EXPORT extern const char kAshEnableMirroredScreen[]; -ASH_EXPORT extern const char kAshDisableStableOverviewOrder[]; +ASH_EXPORT extern const char kAshForceEnablePalette[]; ASH_EXPORT extern const char kAshHideNotificationsForFactory[]; ASH_EXPORT extern const char kAshMaterialDesign[]; ASH_EXPORT extern const char kAshMaterialDesignDisabled[];
diff --git a/ash/common/frame/caption_buttons/frame_caption_button.cc b/ash/common/frame/caption_buttons/frame_caption_button.cc index ca343925..0d26e0d 100644 --- a/ash/common/frame/caption_buttons/frame_caption_button.cc +++ b/ash/common/frame/caption_buttons/frame_caption_button.cc
@@ -127,13 +127,13 @@ if (crossfade_icon_alpha > 0 && !crossfade_icon_image_.isNull()) { gfx::Canvas icon_canvas(icon_image_.size(), canvas->image_scale(), false); - cc::PaintFlags paint; - paint.setAlpha(icon_alpha); - icon_canvas.DrawImageInt(icon_image_, 0, 0, paint); + cc::PaintFlags flags; + flags.setAlpha(icon_alpha); + icon_canvas.DrawImageInt(icon_image_, 0, 0, flags); - paint.setAlpha(crossfade_icon_alpha); - paint.setBlendMode(SkBlendMode::kPlus); - icon_canvas.DrawImageInt(crossfade_icon_image_, 0, 0, paint); + flags.setAlpha(crossfade_icon_alpha); + flags.setBlendMode(SkBlendMode::kPlus); + icon_canvas.DrawImageInt(crossfade_icon_image_, 0, 0, flags); PaintCentered(canvas, gfx::ImageSkia(icon_canvas.ExtractImageRep()), alpha_); @@ -182,10 +182,10 @@ alpha *= inactive_alpha; } - cc::PaintFlags paint; - paint.setAlpha(alpha); + cc::PaintFlags flags; + flags.setAlpha(alpha); canvas->DrawImageInt(to_center, (width() - to_center.width()) / 2, - (height() - to_center.height()) / 2, paint); + (height() - to_center.height()) / 2, flags); } } // namespace ash
diff --git a/ash/common/frame/default_header_painter.cc b/ash/common/frame/default_header_painter.cc index 4def3b3e..bf95ba97 100644 --- a/ash/common/frame/default_header_painter.cc +++ b/ash/common/frame/default_header_painter.cc
@@ -44,7 +44,7 @@ // Tiles an image into an area, rounding the top corners. void TileRoundRect(gfx::Canvas* canvas, - const cc::PaintFlags& paint, + const cc::PaintFlags& flags, const gfx::Rect& bounds, int corner_radius) { SkRect rect = gfx::RectToSkRect(bounds); @@ -59,7 +59,7 @@ 0}; // bottom-left SkPath path; path.addRoundRect(rect, radii, SkPath::kCW_Direction); - canvas->DrawPath(path, paint); + canvas->DrawPath(path, flags); } // Returns the FontList to use for the title. @@ -138,12 +138,12 @@ ? 0 : HeaderPainterUtil::GetTopCornerRadiusWhenRestored(); - cc::PaintFlags paint; + cc::PaintFlags flags; int active_alpha = activation_animation_->CurrentValueBetween(0, 255); - paint.setColor(color_utils::AlphaBlend(active_frame_color_, + flags.setColor(color_utils::AlphaBlend(active_frame_color_, inactive_frame_color_, active_alpha)); - paint.setAntiAlias(true); - TileRoundRect(canvas, paint, GetLocalBounds(), corner_radius); + flags.setAntiAlias(true); + TileRoundRect(canvas, flags, GetLocalBounds(), corner_radius); if (!frame_->IsMaximized() && !frame_->IsFullscreen() && mode_ == MODE_INACTIVE && !UsesCustomFrameColors()) { @@ -269,10 +269,10 @@ gfx::ScopedCanvas scoped_canvas(canvas); const float scale = canvas->UndoDeviceScaleFactor(); gfx::RectF rect(0, painted_height_ * scale - 1, view_->width() * scale, 1); - cc::PaintFlags paint; - paint.setColor((mode_ == MODE_ACTIVE) ? kHeaderContentSeparatorColor + cc::PaintFlags flags; + flags.setColor((mode_ == MODE_ACTIVE) ? kHeaderContentSeparatorColor : kHeaderContentSeparatorInactiveColor); - canvas->sk_canvas()->drawRect(gfx::RectFToSkRect(rect), paint); + canvas->sk_canvas()->drawRect(gfx::RectFToSkRect(rect), flags); } bool DefaultHeaderPainter::ShouldUseLightImages() {
diff --git a/ash/common/palette_delegate.h b/ash/common/palette_delegate.h index c0dbbc2..9ebfe242 100644 --- a/ash/common/palette_delegate.h +++ b/ash/common/palette_delegate.h
@@ -20,7 +20,6 @@ using EnableListener = base::Callback<void(bool)>; using EnableListenerSubscription = base::CallbackList<void(bool)>::Subscription; - using OnStylusStateChangedCallback = base::Callback<void(ui::StylusState)>; virtual ~PaletteDelegate() {} @@ -36,10 +35,6 @@ // Returns true if there is a note-taking application available. virtual bool HasNoteApp() = 0; - // Set callback that is run when a stylus is inserted or removed. - virtual void SetStylusStateChangedCallback( - const OnStylusStateChangedCallback& on_stylus_state_changed) = 0; - // Returns true if the palette should be automatically opened on an eject // event. virtual bool ShouldAutoOpenPalette() = 0;
diff --git a/ash/common/shelf/app_list_button.cc b/ash/common/shelf/app_list_button.cc index df9544c..ad6a5d6 100644 --- a/ash/common/shelf/app_list_button.cc +++ b/ash/common/shelf/app_list_button.cc
@@ -164,11 +164,11 @@ gfx::PointF circle_center(GetCenterPoint()); // Paint the circular background. - cc::PaintFlags bg_paint; - bg_paint.setColor(SkColorSetA(kShelfBaseColor, background_alpha_)); - bg_paint.setFlags(cc::PaintFlags::kAntiAlias_Flag); - bg_paint.setStyle(cc::PaintFlags::kFill_Style); - canvas->DrawCircle(circle_center, kAppListButtonRadius, bg_paint); + cc::PaintFlags bg_flags; + bg_flags.setColor(SkColorSetA(kShelfBaseColor, background_alpha_)); + bg_flags.setFlags(cc::PaintFlags::kAntiAlias_Flag); + bg_flags.setStyle(cc::PaintFlags::kFill_Style); + canvas->DrawCircle(circle_center, kAppListButtonRadius, bg_flags); // Paint a white ring as the foreground. The ceil/dsf math assures that the // ring draws sharply and is centered at all scale factors. @@ -178,15 +178,15 @@ const float dsf = canvas->UndoDeviceScaleFactor(); circle_center.Scale(dsf); - cc::PaintFlags fg_paint; - fg_paint.setFlags(cc::PaintFlags::kAntiAlias_Flag); - fg_paint.setStyle(cc::PaintFlags::kStroke_Style); - fg_paint.setColor(kShelfIconColor); + cc::PaintFlags fg_flags; + fg_flags.setFlags(cc::PaintFlags::kAntiAlias_Flag); + fg_flags.setStyle(cc::PaintFlags::kStroke_Style); + fg_flags.setColor(kShelfIconColor); const float thickness = std::ceil(kRingThicknessDp * dsf); const float radius = std::ceil(kRingOuterRadiusDp * dsf) - thickness / 2; - fg_paint.setStrokeWidth(thickness); + fg_flags.setStrokeWidth(thickness); // Make sure the center of the circle lands on pixel centers. - canvas->DrawCircle(circle_center, radius, fg_paint); + canvas->DrawCircle(circle_center, radius, fg_flags); } void AppListButton::PaintAppListButton(gfx::Canvas* canvas,
diff --git a/ash/common/shelf/app_list_shelf_item_delegate.cc b/ash/common/shelf/app_list_shelf_item_delegate.cc index 244d3e6..6e1f003 100644 --- a/ash/common/shelf/app_list_shelf_item_delegate.cc +++ b/ash/common/shelf/app_list_shelf_item_delegate.cc
@@ -38,10 +38,10 @@ return ShelfItemDelegate::kAppListMenuShown; } -ui::SimpleMenuModel* AppListShelfItemDelegate::CreateApplicationMenu( +ShelfAppMenuItemList AppListShelfItemDelegate::GetAppMenuItems( int event_flags) { // AppList does not show an application menu. - return nullptr; + return ShelfAppMenuItemList(); } void AppListShelfItemDelegate::Close() {}
diff --git a/ash/common/shelf/app_list_shelf_item_delegate.h b/ash/common/shelf/app_list_shelf_item_delegate.h index 422f1bab..775d3be4 100644 --- a/ash/common/shelf/app_list_shelf_item_delegate.h +++ b/ash/common/shelf/app_list_shelf_item_delegate.h
@@ -24,7 +24,7 @@ // ShelfItemDelegate: ShelfItemDelegate::PerformedAction ItemSelected( const ui::Event& event) override; - ui::SimpleMenuModel* CreateApplicationMenu(int event_flags) override; + ShelfAppMenuItemList GetAppMenuItems(int event_flags) override; void Close() override; private:
diff --git a/ash/common/shelf/overflow_button.cc b/ash/common/shelf/overflow_button.cc index 73dddf57..1b656ac0 100644 --- a/ash/common/shelf/overflow_button.cc +++ b/ash/common/shelf/overflow_button.cc
@@ -119,11 +119,10 @@ void OverflowButton::PaintBackground(gfx::Canvas* canvas, const gfx::Rect& bounds) { if (MaterialDesignController::IsShelfMaterial()) { - cc::PaintFlags background_paint; - background_paint.setFlags(cc::PaintFlags::kAntiAlias_Flag); - background_paint.setColor(SkColorSetA(kShelfBaseColor, background_alpha_)); - canvas->DrawRoundRect(bounds, kOverflowButtonCornerRadius, - background_paint); + cc::PaintFlags flags; + flags.setFlags(cc::PaintFlags::kAntiAlias_Flag); + flags.setColor(SkColorSetA(kShelfBaseColor, background_alpha_)); + canvas->DrawRoundRect(bounds, kOverflowButtonCornerRadius, flags); } else { ResourceBundle& rb = ResourceBundle::GetSharedInstance(); const gfx::ImageSkia* background =
diff --git a/ash/common/shelf/shelf_application_menu_model.cc b/ash/common/shelf/shelf_application_menu_model.cc new file mode 100644 index 0000000..331f0d5 --- /dev/null +++ b/ash/common/shelf/shelf_application_menu_model.cc
@@ -0,0 +1,69 @@ +// 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 "ash/common/shelf/shelf_application_menu_model.h" + +#include <stddef.h> + +#include <limits> +#include <utility> + +#include "ash/public/cpp/shelf_application_menu_item.h" +#include "base/metrics/histogram_macros.h" + +namespace { + +const int kInvalidCommandId = std::numeric_limits<int>::max(); + +} // namespace + +namespace ash { + +ShelfApplicationMenuModel::ShelfApplicationMenuModel( + const base::string16& title, + ShelfAppMenuItemList items) + : ui::SimpleMenuModel(this), items_(std::move(items)) { + AddSeparator(ui::SPACING_SEPARATOR); + AddItem(kInvalidCommandId, title); + AddSeparator(ui::SPACING_SEPARATOR); + + for (size_t i = 0; i < items_.size(); i++) { + ShelfApplicationMenuItem* item = items_[i].get(); + AddItem(i, item->title()); + if (!item->icon().IsEmpty()) + SetIcon(GetIndexOfCommandId(i), item->icon()); + } + + // SimpleMenuModel does not allow two consecutive spacing separator items. + // This only occurs in tests; users should not see menus with no |items_|. + if (!items_.empty()) + AddSeparator(ui::SPACING_SEPARATOR); +} + +ShelfApplicationMenuModel::~ShelfApplicationMenuModel() {} + +bool ShelfApplicationMenuModel::IsCommandIdChecked(int command_id) const { + return false; +} + +bool ShelfApplicationMenuModel::IsCommandIdEnabled(int command_id) const { + return command_id >= 0 && static_cast<size_t>(command_id) < items_.size(); +} + +void ShelfApplicationMenuModel::ExecuteCommand(int command_id, + int event_flags) { + DCHECK(IsCommandIdEnabled(command_id)); + items_[command_id]->Execute(event_flags); + RecordMenuItemSelectedMetrics(command_id, items_.size()); +} + +void ShelfApplicationMenuModel::RecordMenuItemSelectedMetrics( + int command_id, + int num_menu_items_enabled) { + UMA_HISTOGRAM_COUNTS_100("Ash.Shelf.Menu.SelectedMenuItemIndex", command_id); + UMA_HISTOGRAM_COUNTS_100("Ash.Shelf.Menu.NumItemsEnabledUponSelection", + num_menu_items_enabled); +} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_application_menu_model.h b/ash/common/shelf/shelf_application_menu_model.h new file mode 100644 index 0000000..ff865fe --- /dev/null +++ b/ash/common/shelf/shelf_application_menu_model.h
@@ -0,0 +1,58 @@ +// 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 ASH_COMMON_SHELF_SHELF_APPLICATION_MENU_MODEL_H_ +#define ASH_COMMON_SHELF_SHELF_APPLICATION_MENU_MODEL_H_ + +#include <memory> +#include <vector> + +#include "ash/ash_export.h" +#include "ash/public/cpp/shelf_application_menu_item.h" +#include "base/macros.h" +#include "ui/base/models/simple_menu_model.h" + +class ShelfApplicationMenuModelTestAPI; + +namespace ash { + +// A menu model listing open applications associated with a shelf item. Layout: +// +---------------------------+ +// | | +// | App Title | +// | | +// | [Icon] Item Title | +// | [Icon] Item Title | +// | | +// +---------------------------+ +class ASH_EXPORT ShelfApplicationMenuModel + : public ui::SimpleMenuModel, + public ui::SimpleMenuModel::Delegate { + public: + // Makes a menu with a |title|, separators, and the specified |items|. + ShelfApplicationMenuModel(const base::string16& title, + ShelfAppMenuItemList items); + ~ShelfApplicationMenuModel() override; + + // ui::SimpleMenuModel::Delegate: + bool IsCommandIdChecked(int command_id) const override; + bool IsCommandIdEnabled(int command_id) const override; + void ExecuteCommand(int command_id, int event_flags) override; + + private: + friend class ShelfApplicationMenuModelTestAPI; + + // Records UMA metrics when a menu item is selected. + void RecordMenuItemSelectedMetrics(int command_id, + int num_menu_items_enabled); + + // The list of menu items as returned from the shelf item's controller. + ShelfAppMenuItemList items_; + + DISALLOW_COPY_AND_ASSIGN(ShelfApplicationMenuModel); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_APPLICATION_MENU_MODEL_H_
diff --git a/ash/common/shelf/shelf_application_menu_model_unittest.cc b/ash/common/shelf/shelf_application_menu_model_unittest.cc new file mode 100644 index 0000000..704f473 --- /dev/null +++ b/ash/common/shelf/shelf_application_menu_model_unittest.cc
@@ -0,0 +1,130 @@ +// 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 "ash/common/shelf/shelf_application_menu_model.h" + +#include <utility> + +#include "ash/public/cpp/shelf_application_menu_item.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/test/histogram_tester.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace ash { + +namespace { + +const char kNumItemsEnabledHistogramName[] = + "Ash.Shelf.Menu.NumItemsEnabledUponSelection"; + +const char kSelectedMenuItemIndexHistogramName[] = + "Ash.Shelf.Menu.SelectedMenuItemIndex"; + +} // namespace + +// Test API to provide internal access to a ShelfApplicationMenuModel. +class ShelfApplicationMenuModelTestAPI { + public: + // Creates a test api to access the internals of the |menu|. + explicit ShelfApplicationMenuModelTestAPI(ShelfApplicationMenuModel* menu) + : menu_(menu) {} + ~ShelfApplicationMenuModelTestAPI() {} + + // Give public access to this metrics recording functions. + void RecordMenuItemSelectedMetrics(int command_id, + int num_menu_items_enabled) { + menu_->RecordMenuItemSelectedMetrics(command_id, num_menu_items_enabled); + } + + private: + // The ShelfApplicationMenuModel to provide internal access to. Not owned. + ShelfApplicationMenuModel* menu_; + + DISALLOW_COPY_AND_ASSIGN(ShelfApplicationMenuModelTestAPI); +}; + +// Verifies the menu contents given an empty item list. +TEST(ShelfApplicationMenuModelTest, VerifyContentsWithNoMenuItems) { + base::string16 title = base::ASCIIToUTF16("title"); + ShelfApplicationMenuModel menu(title, ShelfAppMenuItemList()); + // Expect the title with separators. + ASSERT_EQ(static_cast<int>(3), menu.GetItemCount()); + EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(0)); + EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu.GetTypeAt(1)); + EXPECT_EQ(title, menu.GetLabelAt(1)); + EXPECT_FALSE(menu.IsEnabledAt(1)); + EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(2)); +} + +// Verifies the menu contents given a non-empty item list. +TEST(ShelfApplicationMenuModelTest, VerifyContentsWithMenuItems) { + ShelfAppMenuItemList items; + base::string16 title1 = base::ASCIIToUTF16("title1"); + base::string16 title2 = base::ASCIIToUTF16("title2"); + base::string16 title3 = base::ASCIIToUTF16("title3"); + items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(title1)); + items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(title2)); + items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(title3)); + + base::string16 title = base::ASCIIToUTF16("title"); + ShelfApplicationMenuModel menu(title, std::move(items)); + ShelfApplicationMenuModelTestAPI menu_test_api(&menu); + + // Expect the title with separators, the enabled items, and another separator. + ASSERT_EQ(static_cast<int>(7), menu.GetItemCount()); + EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(0)); + EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu.GetTypeAt(1)); + EXPECT_EQ(title, menu.GetLabelAt(1)); + EXPECT_FALSE(menu.IsEnabledAt(1)); + EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(2)); + EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu.GetTypeAt(3)); + EXPECT_EQ(title1, menu.GetLabelAt(3)); + EXPECT_TRUE(menu.IsEnabledAt(3)); + EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu.GetTypeAt(4)); + EXPECT_EQ(title2, menu.GetLabelAt(4)); + EXPECT_TRUE(menu.IsEnabledAt(4)); + EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu.GetTypeAt(5)); + EXPECT_EQ(title3, menu.GetLabelAt(5)); + EXPECT_TRUE(menu.IsEnabledAt(5)); + EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(6)); +} + +// Verifies RecordMenuItemSelectedMetrics uses the correct histogram buckets. +TEST(ShelfApplicationMenuModelTest, VerifyHistogramBuckets) { + const int kCommandId = 3; + const int kNumMenuItemsEnabled = 7; + + base::HistogramTester histogram_tester; + + ShelfAppMenuItemList items; + ShelfApplicationMenuModel menu(base::ASCIIToUTF16("title"), std::move(items)); + ShelfApplicationMenuModelTestAPI menu_test_api(&menu); + menu_test_api.RecordMenuItemSelectedMetrics(kCommandId, kNumMenuItemsEnabled); + + histogram_tester.ExpectTotalCount(kNumItemsEnabledHistogramName, 1); + histogram_tester.ExpectBucketCount(kNumItemsEnabledHistogramName, + kNumMenuItemsEnabled, 1); + + histogram_tester.ExpectTotalCount(kSelectedMenuItemIndexHistogramName, 1); + histogram_tester.ExpectBucketCount(kSelectedMenuItemIndexHistogramName, + kCommandId, 1); +} + +// Verify histogram data is recorded when ExecuteCommand is called. +TEST(ShelfApplicationMenuModelTest, VerifyHistogramOnExecute) { + base::HistogramTester histogram_tester; + + ShelfAppMenuItemList items; + base::string16 title = base::ASCIIToUTF16("title"); + items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(title)); + ShelfApplicationMenuModel menu(title, std::move(items)); + menu.ExecuteCommand(0, 0); + + histogram_tester.ExpectTotalCount(kNumItemsEnabledHistogramName, 1); + histogram_tester.ExpectTotalCount(kSelectedMenuItemIndexHistogramName, 1); +} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_button.cc b/ash/common/shelf/shelf_button.cc index c91cd352..5e1fc2d 100644 --- a/ash/common/shelf/shelf_button.cc +++ b/ash/common/shelf/shelf_button.cc
@@ -60,13 +60,13 @@ // Paints an activity indicator on |canvas| whose |size| is specified in DIP. void PaintIndicatorOnCanvas(gfx::Canvas* canvas, const gfx::Size& size) { - cc::PaintFlags paint; - paint.setColor(kIndicatorColor); - paint.setFlags(cc::PaintFlags::kAntiAlias_Flag); + cc::PaintFlags flags; + flags.setColor(kIndicatorColor); + flags.setFlags(cc::PaintFlags::kAntiAlias_Flag); canvas->DrawCircle( gfx::Point(size.width() / 2, size.height() - kIndicatorOffsetFromBottom - kIndicatorRadius), - kIndicatorRadius, paint); + kIndicatorRadius, flags); } // Simple AnimationDelegate that owns a single ThrobAnimation instance to
diff --git a/ash/common/shelf/shelf_controller.cc b/ash/common/shelf/shelf_controller.cc index 05def9c..02e6f1a 100644 --- a/ash/common/shelf/shelf_controller.cc +++ b/ash/common/shelf/shelf_controller.cc
@@ -53,36 +53,6 @@ void set_title(const base::string16& title) { title_ = title; } private: - // This application menu model for ShelfItemDelegateMus lists open windows. - class ShelfMenuModelMus : public ui::SimpleMenuModel, - public ui::SimpleMenuModel::Delegate { - public: - explicit ShelfMenuModelMus(ShelfItemDelegateMus* item_delegate) - : ui::SimpleMenuModel(this), item_delegate_(item_delegate) { - AddSeparator(ui::SPACING_SEPARATOR); - AddItem(0, item_delegate_->title()); - AddSeparator(ui::SPACING_SEPARATOR); - for (const auto& window : item_delegate_->window_id_to_title()) - AddItem(window.first, window.second); - AddSeparator(ui::SPACING_SEPARATOR); - } - ~ShelfMenuModelMus() override {} - - // ui::SimpleMenuModel::Delegate: - bool IsCommandIdChecked(int command_id) const override { return false; } - bool IsCommandIdEnabled(int command_id) const override { - return command_id > 0; - } - void ExecuteCommand(int command_id, int event_flags) override { - NOTIMPLEMENTED(); - } - - private: - ShelfItemDelegateMus* item_delegate_; - - DISALLOW_COPY_AND_ASSIGN(ShelfMenuModelMus); - }; - // ShelfItemDelegate: ShelfItemDelegate::PerformedAction ItemSelected( const ui::Event& event) override { @@ -97,8 +67,13 @@ return kNoAction; } - ui::SimpleMenuModel* CreateApplicationMenu(int event_flags) override { - return new ShelfMenuModelMus(this); + ShelfAppMenuItemList GetAppMenuItems(int event_flags) override { + ShelfAppMenuItemList items; + for (const auto& window : window_id_to_title_) { + items.push_back( + base::MakeUnique<ShelfApplicationMenuItem>(window.second)); + } + return items; } void Close() override { NOTIMPLEMENTED(); }
diff --git a/ash/common/shelf/shelf_item_delegate.h b/ash/common/shelf/shelf_item_delegate.h index 424e0de..43605db2 100644 --- a/ash/common/shelf/shelf_item_delegate.h +++ b/ash/common/shelf/shelf_item_delegate.h
@@ -6,11 +6,10 @@ #define ASH_COMMON_SHELF_SHELF_ITEM_DELEGATE_H_ #include "ash/ash_export.h" -#include "base/strings/string16.h" +#include "ash/public/cpp/shelf_application_menu_item.h" namespace ui { class Event; -class SimpleMenuModel; } namespace ash { @@ -43,16 +42,9 @@ // Returns the action performed by selecting the item. virtual PerformedAction ItemSelected(const ui::Event& event) = 0; - // Returns the application menu model for the specified item. There are three - // possible return values: - // - A return of NULL indicates that no menu is wanted for this item. - // - A return of a menu with one item means that only the name of the - // application/item was added and there are no active applications. - // Note: This is useful for hover menus which also show context help. - // - A list containing the title and the active list of items. - // The caller takes ownership of the returned model. + // Returns any application menu items that should appear for this shelf item. // |event_flags| specifies the flags of the event which triggered this menu. - virtual ui::SimpleMenuModel* CreateApplicationMenu(int event_flags) = 0; + virtual ShelfAppMenuItemList GetAppMenuItems(int event_flags) = 0; // Closes all windows associated with this item. virtual void Close() = 0;
diff --git a/ash/common/shelf/shelf_view.cc b/ash/common/shelf/shelf_view.cc index 82d34988..8ab6225 100644 --- a/ash/common/shelf/shelf_view.cc +++ b/ash/common/shelf/shelf_view.cc
@@ -14,6 +14,7 @@ #include "ash/common/shelf/overflow_bubble.h" #include "ash/common/shelf/overflow_bubble_view.h" #include "ash/common/shelf/overflow_button.h" +#include "ash/common/shelf/shelf_application_menu_model.h" #include "ash/common/shelf/shelf_button.h" #include "ash/common/shelf/shelf_constants.h" #include "ash/common/shelf/shelf_delegate.h" @@ -26,6 +27,7 @@ #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "base/auto_reset.h" +#include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "grit/ash_strings.h" #include "ui/accessibility/ax_node_data.h" @@ -1613,18 +1615,21 @@ const ui::Event& event, views::InkDrop* ink_drop) { ShelfItemDelegate* item_delegate = model_->GetShelfItemDelegate(item.id); - std::unique_ptr<ui::MenuModel> list_menu_model( - item_delegate->CreateApplicationMenu(event.flags())); + ShelfAppMenuItemList menu_items = + item_delegate->GetAppMenuItems(event.flags()); - // Make sure we have a menu and it has at least two items in addition to the - // application title and the 3 spacing separators. - if (!list_menu_model.get() || list_menu_model->GetItemCount() <= 5) + // The application list menu should only show for two or more items; return + // false here to ensure that other behavior is triggered (eg. activating or + // minimizing a single associated window, or launching a pinned shelf item). + if (menu_items.size() < 2) return false; ink_drop->AnimateToState(views::InkDropState::ACTIVATED); context_menu_id_ = item.id; - ShowMenu(std::move(list_menu_model), source, gfx::Point(), false, - ui::GetMenuSourceTypeForEvent(event), ink_drop); + ShowMenu(base::MakeUnique<ShelfApplicationMenuModel>(item.title, + std::move(menu_items)), + source, gfx::Point(), false, ui::GetMenuSourceTypeForEvent(event), + ink_drop); return true; }
diff --git a/ash/common/shelf/shelf_widget.cc b/ash/common/shelf/shelf_widget.cc index bc10b09..192cb8ac 100644 --- a/ash/common/shelf/shelf_widget.cc +++ b/ash/common/shelf/shelf_widget.cc
@@ -140,8 +140,8 @@ } const gfx::Rect dock_bounds( shelf_widget_->shelf_layout_manager()->dock_bounds()); - cc::PaintFlags paint; - paint.setAlpha(asset_background_alpha_); + cc::PaintFlags flags; + flags.setAlpha(asset_background_alpha_); canvas->DrawImageInt( shelf_background, 0, 0, shelf_background.width(), shelf_background.height(), @@ -149,7 +149,7 @@ ? dock_bounds.width() : 0, 0, horizontal ? width() - dock_bounds.width() : width(), height(), false, - paint); + flags); if (horizontal && dock_bounds.width() > 0) { // The part of the shelf background that is in the corner below the docked // windows close to the work area is an arched gradient that blends @@ -162,7 +162,7 @@ canvas->DrawImageInt( shelf_corner, 0, 0, shelf_corner.width(), shelf_corner.height(), dock_bounds.x() > 0 ? dock_bounds.x() : dock_bounds.width() - height(), - 0, height(), height(), false, paint); + 0, height(), height(), false, flags); // The part of the shelf background that is just below the docked windows // is drawn using the last (lowest) 1-pixel tall strip of the image asset. // This avoids showing the border 3D shadow between the shelf and the @@ -171,7 +171,7 @@ shelf_background.width(), 1, dock_bounds.x() > 0 ? dock_bounds.x() + height() : 0, 0, dock_bounds.width() - height(), height(), false, - paint); + flags); } gfx::Rect black_rect = shelf_widget_->shelf_layout_manager()->SelectValueForShelfAlignment(
diff --git a/ash/common/shelf/shelf_window_watcher_item_delegate.cc b/ash/common/shelf/shelf_window_watcher_item_delegate.cc index dfee1468..2ab81c86 100644 --- a/ash/common/shelf/shelf_window_watcher_item_delegate.cc +++ b/ash/common/shelf/shelf_window_watcher_item_delegate.cc
@@ -55,9 +55,10 @@ return kExistingWindowActivated; } -ui::SimpleMenuModel* ShelfWindowWatcherItemDelegate::CreateApplicationMenu( +ShelfAppMenuItemList ShelfWindowWatcherItemDelegate::GetAppMenuItems( int event_flags) { - return nullptr; + // Return an empty item list to avoid showing an application menu. + return ShelfAppMenuItemList(); } void ShelfWindowWatcherItemDelegate::Close() {
diff --git a/ash/common/shelf/shelf_window_watcher_item_delegate.h b/ash/common/shelf/shelf_window_watcher_item_delegate.h index 592ba735..2ce7db5 100644 --- a/ash/common/shelf/shelf_window_watcher_item_delegate.h +++ b/ash/common/shelf/shelf_window_watcher_item_delegate.h
@@ -13,7 +13,8 @@ class WmWindow; -// ShelfItemDelegate for the items created by ShelfWindowWatcher. +// ShelfItemDelegate for the items created by ShelfWindowWatcher, for example: +// The Chrome OS settings window, task manager window, and panel windows. class ShelfWindowWatcherItemDelegate : public ShelfItemDelegate { public: ShelfWindowWatcherItemDelegate(ShelfID id, WmWindow* window); @@ -23,7 +24,7 @@ // ShelfItemDelegate overrides: ShelfItemDelegate::PerformedAction ItemSelected( const ui::Event& event) override; - ui::SimpleMenuModel* CreateApplicationMenu(int event_flags) override; + ShelfAppMenuItemList GetAppMenuItems(int event_flags) override; void Close() override; ShelfID id_;
diff --git a/ash/common/system/chromeos/audio/audio_detailed_view.cc b/ash/common/system/chromeos/audio/audio_detailed_view.cc index 2069c49..b1ecca5 100644 --- a/ash/common/system/chromeos/audio/audio_detailed_view.cc +++ b/ash/common/system/chromeos/audio/audio_detailed_view.cc
@@ -5,7 +5,6 @@ #include "ash/common/system/chromeos/audio/audio_detailed_view.h" #include "ash/common/material_design/material_design_controller.h" -#include "ash/common/system/tray/fixed_sized_scroll_view.h" #include "ash/common/system/tray/hover_highlight_view.h" #include "ash/common/system/tray/tray_constants.h" #include "ash/common/system/tray/tray_popup_utils.h" @@ -22,6 +21,7 @@ #include "ui/views/border.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" +#include "ui/views/controls/scroll_view.h" #include "ui/views/controls/separator.h" namespace {
diff --git a/ash/common/system/chromeos/audio/volume_view.cc b/ash/common/system/chromeos/audio/volume_view.cc index bceef1fa..cd9ad59 100644 --- a/ash/common/system/chromeos/audio/volume_view.cc +++ b/ash/common/system/chromeos/audio/volume_view.cc
@@ -185,9 +185,8 @@ more_button_->SetFocusBehavior(FocusBehavior::NEVER); device_type_ = TrayPopupUtils::CreateMoreImageView(); - more_button_->SetBorder(views::CreateEmptyBorder( - 0, GetTrayConstant(TRAY_POPUP_ITEM_MORE_REGION_HORIZONTAL_INSET), 0, - GetTrayConstant(TRAY_POPUP_ITEM_MORE_REGION_HORIZONTAL_INSET))); + more_button_->SetBorder(views::CreateEmptyBorder(gfx::Insets( + 0, GetTrayConstant(TRAY_POPUP_ITEM_MORE_REGION_HORIZONTAL_INSET)))); more_button_->AddChildView(device_type_); views::ImageView* more_arrow = TrayPopupUtils::CreateMoreImageView();
diff --git a/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc b/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc index 3fade7b..559b563 100644 --- a/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc +++ b/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc
@@ -6,7 +6,6 @@ #include "ash/common/material_design/material_design_controller.h" #include "ash/common/session/session_state_delegate.h" -#include "ash/common/system/tray/fixed_sized_scroll_view.h" #include "ash/common/system/tray/hover_highlight_view.h" #include "ash/common/system/tray/system_tray.h" #include "ash/common/system/tray/system_tray_delegate.h" @@ -34,6 +33,7 @@ #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" #include "ui/views/controls/progress_bar.h" +#include "ui/views/controls/scroll_view.h" #include "ui/views/controls/separator.h" #include "ui/views/layout/box_layout.h" @@ -323,24 +323,32 @@ } } - AppendSameTypeDevicesToScrollList(connected_devices_, true, true, - bluetooth_enabled); - AppendSameTypeDevicesToScrollList(connecting_devices_, true, false, - bluetooth_enabled); - AppendSameTypeDevicesToScrollList(paired_not_connected_devices_, false, - false, bluetooth_enabled); + // Add paired devices (and their section header in MD) in the list. + size_t num_paired_devices = connected_devices_.size() + + connecting_devices_.size() + + paired_not_connected_devices_.size(); + if (num_paired_devices > 0) { + if (UseMd()) + AddSubHeader(IDS_ASH_STATUS_TRAY_BLUETOOTH_PAIRED_DEVICES); + AppendSameTypeDevicesToScrollList(connected_devices_, true, true, + bluetooth_enabled); + AppendSameTypeDevicesToScrollList(connecting_devices_, true, false, + bluetooth_enabled); + AppendSameTypeDevicesToScrollList(paired_not_connected_devices_, false, + false, bluetooth_enabled); + } + + // Add paired devices (and their section header in MD) in the list. if (discovered_not_paired_devices_.size() > 0) { if (UseMd()) { - if (scroll_content()->has_children()) { - scroll_content()->AddChildView( - TrayPopupUtils::CreateListItemSeparator(false)); - } + if (num_paired_devices > 0) + AddSubHeader(IDS_ASH_STATUS_TRAY_BLUETOOTH_UNPAIRED_DEVICES); } else { AddScrollSeparator(); } + AppendSameTypeDevicesToScrollList(discovered_not_paired_devices_, false, + false, bluetooth_enabled); } - AppendSameTypeDevicesToScrollList(discovered_not_paired_devices_, false, - false, bluetooth_enabled); // Show user Bluetooth state if there is no bluetooth devices in list. if (device_map_.size() == 0) { @@ -407,6 +415,19 @@ return container; } + void AddSubHeader(int message_id) { + TriView* header = TrayPopupUtils::CreateSubHeaderRowView(); + TrayPopupUtils::ConfigureAsStickyHeader(header); + + views::Label* label = TrayPopupUtils::CreateDefaultLabel(); + label->SetText(l10n_util::GetStringUTF16(message_id)); + TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::SUB_HEADER); + style.SetupLabel(label); + header->AddView(TriView::Container::CENTER, label); + + scroll_content()->AddChildView(header); + } + void SetupConnectedItemMd(HoverHighlightView* container, const base::string16& text, const gfx::ImageSkia& image) { @@ -497,7 +518,7 @@ container->AddCheckableLabel(display_name, true /* highlight */, false); } scroll_content()->SizeToPreferredSize(); - static_cast<views::View*>(scroller())->Layout(); + scroller()->Layout(); } }
diff --git a/ash/common/system/chromeos/cast/tray_cast.cc b/ash/common/system/chromeos/cast/tray_cast.cc index be5df75..0e3705c 100644 --- a/ash/common/system/chromeos/cast/tray_cast.cc +++ b/ash/common/system/chromeos/cast/tray_cast.cc
@@ -15,7 +15,6 @@ #include "ash/common/shelf/wm_shelf_util.h" #include "ash/common/system/chromeos/screen_security/screen_tray_item.h" #include "ash/common/system/tray/fixed_sized_image_view.h" -#include "ash/common/system/tray/fixed_sized_scroll_view.h" #include "ash/common/system/tray/hover_highlight_view.h" #include "ash/common/system/tray/system_tray.h" #include "ash/common/system/tray/system_tray_delegate.h" @@ -43,6 +42,7 @@ #include "ui/views/controls/button/button.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" +#include "ui/views/controls/scroll_view.h" #include "ui/views/layout/box_layout.h" #include "ui/views/layout/fill_layout.h" @@ -420,7 +420,7 @@ } scroll_content()->SizeToPreferredSize(); - static_cast<views::View*>(scroller())->Layout(); + scroller()->Layout(); } views::View* CastDetailedView::AddToReceiverList(
diff --git a/ash/common/system/chromeos/ime_menu/ime_list_view.cc b/ash/common/system/chromeos/ime_menu/ime_list_view.cc index 670f4f96..e858d69 100644 --- a/ash/common/system/chromeos/ime_menu/ime_list_view.cc +++ b/ash/common/system/chromeos/ime_menu/ime_list_view.cc
@@ -180,7 +180,7 @@ ~MaterialKeyboardStatusRowView() override {} - const views::Button* toggle() const { return toggle_; } + views::Button* toggle() const { return toggle_; } bool is_toggled() const { return toggle_->is_on(); } protected: @@ -456,4 +456,13 @@ } } +ImeListViewTestApi::ImeListViewTestApi(ImeListView* ime_list_view) + : ime_list_view_(ime_list_view) {} + +ImeListViewTestApi::~ImeListViewTestApi() {} + +views::View* ImeListViewTestApi::GetToggleView() const { + return ime_list_view_->material_keyboard_status_view_->toggle(); +} + } // namespace ash
diff --git a/ash/common/system/chromeos/ime_menu/ime_list_view.h b/ash/common/system/chromeos/ime_menu/ime_list_view.h index 35ce9b5..e756514b 100644 --- a/ash/common/system/chromeos/ime_menu/ime_list_view.h +++ b/ash/common/system/chromeos/ime_menu/ime_list_view.h
@@ -5,6 +5,7 @@ #ifndef ASH_COMMON_SYSTEM_CHROMEOS_IME_MENU_IME_LIST_VIEW_H_ #define ASH_COMMON_SYSTEM_CHROMEOS_IME_MENU_IME_LIST_VIEW_H_ +#include "ash/ash_export.h" #include "ash/common/system/tray/ime_info.h" #include "ash/common/system/tray/tray_details_view.h" #include "ui/views/controls/button/button.h" @@ -64,8 +65,7 @@ void VisibilityChanged(View* starting_from, bool is_visible) override; private: - // To allow the test class to access |ime_map_|. - friend class ImeMenuTrayTest; + friend class ImeListViewTestApi; // Appends the IMEs to the scrollable area of the detailed view. void AppendIMEList(const IMEInfoList& list); @@ -113,6 +113,23 @@ DISALLOW_COPY_AND_ASSIGN(ImeListView); }; +class ASH_EXPORT ImeListViewTestApi { + public: + explicit ImeListViewTestApi(ImeListView* ime_list_view); + virtual ~ImeListViewTestApi(); + + views::View* GetToggleView() const; + + const std::map<views::View*, std::string>& ime_map() const { + return ime_list_view_->ime_map_; + } + + private: + ImeListView* ime_list_view_; + + DISALLOW_COPY_AND_ASSIGN(ImeListViewTestApi); +}; + } // namespace ash #endif // ASH_COMMON_SYSTEM_CHROMEOS_IME_MENU_IME_LIST_VIEW_H_
diff --git a/ash/common/system/chromeos/ime_menu/ime_menu_tray.cc b/ash/common/system/chromeos/ime_menu/ime_menu_tray.cc index f2f0c49..fb75f28 100644 --- a/ash/common/system/chromeos/ime_menu/ime_menu_tray.cc +++ b/ash/common/system/chromeos/ime_menu/ime_menu_tray.cc
@@ -11,7 +11,6 @@ #include "ash/common/shelf/wm_shelf.h" #include "ash/common/shelf/wm_shelf_util.h" #include "ash/common/system/chromeos/ime_menu/ime_list_view.h" -#include "ash/common/system/tray/fixed_sized_scroll_view.h" #include "ash/common/system/tray/hover_highlight_view.h" #include "ash/common/system/tray/system_menu_button.h" #include "ash/common/system/tray/system_tray_controller.h" @@ -42,6 +41,7 @@ #include "ui/keyboard/keyboard_util.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/label.h" +#include "ui/views/controls/scroll_view.h" #include "ui/views/controls/separator.h" #include "ui/views/layout/box_layout.h" @@ -345,19 +345,7 @@ protected: void Layout() override { gfx::Range height_range = GetImeListViewRange(); - if (MaterialDesignController::IsSystemTrayMenuMaterial()) { - scroller()->ClipHeightTo(height_range.start(), height_range.end()); - } else { - uint32_t current_height = scroll_content()->height(); - int minimum_menu_width = GetMinimumMenuWidth(); - if (current_height > height_range.end()) { - scroller()->SetFixedSize( - gfx::Size(minimum_menu_width, height_range.end())); - } else if (current_height < height_range.start()) { - scroller()->SetFixedSize( - gfx::Size(minimum_menu_width, height_range.start())); - } - } + scroller()->ClipHeightTo(height_range.start(), height_range.end()); ImeListView::Layout(); }
diff --git a/ash/common/system/chromeos/ime_menu/ime_menu_tray_unittest.cc b/ash/common/system/chromeos/ime_menu/ime_menu_tray_unittest.cc index bc8d7da4..a7ebfc31 100644 --- a/ash/common/system/chromeos/ime_menu/ime_menu_tray_unittest.cc +++ b/ash/common/system/chromeos/ime_menu/ime_menu_tray_unittest.cc
@@ -52,8 +52,8 @@ // Returns true if the IME menu list has been updated with the right IME list. bool IsTrayImeListValid(const std::vector<IMEInfo>& expected_imes, const IMEInfo& expected_current_ime) { - std::map<views::View*, std::string> ime_map = - GetTray()->ime_list_view_->ime_map_; + const std::map<views::View*, std::string>& ime_map = + ImeListViewTestApi(GetTray()->ime_list_view_).ime_map(); if (ime_map.size() != expected_imes.size()) return false;
diff --git a/ash/common/system/chromeos/network/network_icon.cc b/ash/common/system/chromeos/network/network_icon.cc index da1c4098..f407404a 100644 --- a/ash/common/system/chromeos/network/network_icon.cc +++ b/ash/common/system/chromeos/network/network_icon.cc
@@ -395,24 +395,24 @@ return triangle; }; - cc::PaintFlags paint; - paint.setAntiAlias(true); - paint.setStyle(cc::PaintFlags::kFill_Style); + cc::PaintFlags flags; + flags.setAntiAlias(true); + flags.setStyle(cc::PaintFlags::kFill_Style); // Background. Skip drawing for full signal. if (signal_strength_ != kNumNetworkImages - 1) { - paint.setColor(SkColorSetA(color_, kBgAlpha)); - canvas->DrawPath(make_triangle(kFullTriangleSide), paint); + flags.setColor(SkColorSetA(color_, kBgAlpha)); + canvas->DrawPath(make_triangle(kFullTriangleSide), flags); } // Foreground (signal strength). if (signal_strength_ != 0) { - paint.setColor(color_); + flags.setColor(color_); // As a percentage of the bg triangle, the length of one of the short // sides of the fg triangle, indexed by signal strength. static const float kTriangleSidePercents[] = {0.f, 0.5f, 0.625f, 0.75f, 1.f}; canvas->DrawPath(make_triangle(kTriangleSidePercents[signal_strength_] * kFullTriangleSide), - paint); + flags); } }
diff --git a/ash/common/system/chromeos/network/network_state_list_detailed_view.cc b/ash/common/system/chromeos/network/network_state_list_detailed_view.cc index e1f58c1..3a5ce73 100644 --- a/ash/common/system/chromeos/network/network_state_list_detailed_view.cc +++ b/ash/common/system/chromeos/network/network_state_list_detailed_view.cc
@@ -19,7 +19,6 @@ #include "ash/common/system/chromeos/network/vpn_list_view.h" #include "ash/common/system/networking_config_delegate.h" #include "ash/common/system/tray/fixed_sized_image_view.h" -#include "ash/common/system/tray/fixed_sized_scroll_view.h" #include "ash/common/system/tray/hover_highlight_view.h" #include "ash/common/system/tray/system_menu_button.h" #include "ash/common/system/tray/system_tray.h" @@ -29,7 +28,6 @@ #include "ash/common/system/tray/tray_constants.h" #include "ash/common/system/tray/tray_details_view.h" #include "ash/common/system/tray/tray_popup_header_button.h" -#include "ash/common/system/tray/tray_popup_label_button.h" #include "ash/common/system/tray/tri_view.h" #include "ash/common/wm_lookup.h" #include "ash/common/wm_shell.h" @@ -59,6 +57,7 @@ #include "ui/gfx/text_constants.h" #include "ui/views/bubble/bubble_dialog_delegate.h" #include "ui/views/controls/label.h" +#include "ui/views/controls/scroll_view.h" #include "ui/views/layout/box_layout.h" #include "ui/views/layout/fill_layout.h" #include "ui/views/layout/layout_manager.h" @@ -104,23 +103,6 @@ return view; } -bool PolicyProhibitsUnmanaged() { - if (!LoginState::IsInitialized() || !LoginState::Get()->IsUserLoggedIn()) - return false; - bool policy_prohibites_unmanaged = false; - const base::DictionaryValue* global_network_config = - NetworkHandler::Get() - ->managed_network_configuration_handler() - ->GetGlobalConfigFromPolicy( - std::string() /* no username hash, device policy */); - if (global_network_config) { - global_network_config->GetBooleanWithoutPathExpansion( - ::onc::global_network_config::kAllowOnlyPolicyNetworksToConnect, - &policy_prohibites_unmanaged); - } - return policy_prohibites_unmanaged; -} - // TODO(varkha): Consolidate with a similar method in tray_bluetooth.cc. void SetupConnectedItemMd(HoverHighlightView* container, const base::string16& text, @@ -339,13 +321,6 @@ login_(login), prev_wifi_scanning_state_(false), info_icon_(nullptr), - button_wifi_(nullptr), - button_mobile_(nullptr), - other_wifi_(nullptr), - turn_on_wifi_(nullptr), - other_mobile_(nullptr), - settings_(nullptr), - proxy_settings_(nullptr), info_button_md_(nullptr), settings_button_md_(nullptr), proxy_settings_button_md_(nullptr), @@ -373,8 +348,6 @@ void NetworkStateListDetailedView::Update() { UpdateNetworkList(); - UpdateHeaderButtons(); - UpdateNetworkExtra(); Layout(); } @@ -383,13 +356,6 @@ void NetworkStateListDetailedView::Init() { Reset(); info_icon_ = nullptr; - button_wifi_ = nullptr; - button_mobile_ = nullptr; - other_wifi_ = nullptr; - turn_on_wifi_ = nullptr; - other_mobile_ = nullptr; - settings_ = nullptr; - proxy_settings_ = nullptr; info_button_md_ = nullptr; settings_button_md_ = nullptr; proxy_settings_button_md_ = nullptr; @@ -416,56 +382,16 @@ void NetworkStateListDetailedView::HandleButtonPressed(views::Button* sender, const ui::Event& event) { - if (UseMd()) { - if (sender == info_button_md_) { - ToggleInfoBubble(); - return; - } else if (sender == settings_button_md_) { - ShowSettings(); - } else if (sender == proxy_settings_button_md_) { - WmShell::Get()->system_tray_controller()->ShowProxySettings(); - } - - if (owner()->system_tray()) - owner()->system_tray()->CloseSystemBubble(); - return; - } - - if (sender == info_icon_) { + if (sender == info_button_md_) { ToggleInfoBubble(); return; + } else if (sender == settings_button_md_) { + ShowSettings(); + } else if (sender == proxy_settings_button_md_) { + WmShell::Get()->system_tray_controller()->ShowProxySettings(); } - // If the info bubble was visible, close it when some other item is clicked. - ResetInfoBubble(); - bool close_bubble = false; - NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); - if (sender == button_wifi_) { - bool enabled = handler->IsTechnologyEnabled(NetworkTypePattern::WiFi()); - handler->SetTechnologyEnabled(NetworkTypePattern::WiFi(), !enabled, - chromeos::network_handler::ErrorCallback()); - } else if (sender == turn_on_wifi_) { - handler->SetTechnologyEnabled(NetworkTypePattern::WiFi(), true, - chromeos::network_handler::ErrorCallback()); - } else if (sender == button_mobile_) { - ToggleMobile(); - } else if (sender == settings_) { - ShowSettings(); - close_bubble = true; - } else if (sender == proxy_settings_) { - WmShell::Get()->system_tray_controller()->ShowProxySettings(); - close_bubble = true; - } else if (sender == other_mobile_) { - WmShell::Get()->system_tray_controller()->ShowNetworkCreate( - shill::kTypeCellular); - close_bubble = true; - } else if (sender == other_wifi_) { - OnOtherWifiClicked(); - close_bubble = true; - } else { - NOTREACHED(); - } - if (close_bubble && owner()->system_tray()) + if (owner()->system_tray()) owner()->system_tray()->CloseSystemBubble(); } @@ -500,98 +426,37 @@ } void NetworkStateListDetailedView::CreateExtraTitleRowButtons() { - if (UseMd()) { - if (login_ == LoginStatus::LOCKED) - return; - - DCHECK(!info_button_md_); - tri_view()->SetContainerVisible(TriView::Container::END, true); - - info_button_md_ = new SystemMenuButton( - this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuInfoIcon, - IDS_ASH_STATUS_TRAY_NETWORK_INFO); - tri_view()->AddView(TriView::Container::END, info_button_md_); - - if (login_ != LoginStatus::NOT_LOGGED_IN) { - DCHECK(!settings_button_md_); - settings_button_md_ = new SystemMenuButton( - this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuSettingsIcon, - IDS_ASH_STATUS_TRAY_NETWORK_SETTINGS); - - // Allow the user to access settings only if user is logged in - // and showing settings is allowed. There are situations (supervised user - // creation flow) when session is started but UI flow continues within - // login UI, i.e., no browser window is yet avaialable. - if (!WmShell::Get()->system_tray_delegate()->ShouldShowSettings()) - settings_button_md_->SetEnabled(false); - - tri_view()->AddView(TriView::Container::END, settings_button_md_); - } else { - proxy_settings_button_md_ = new SystemMenuButton( - this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuSettingsIcon, - IDS_ASH_STATUS_TRAY_NETWORK_PROXY_SETTINGS); - tri_view()->AddView(TriView::Container::END, proxy_settings_button_md_); - } - + if (login_ == LoginStatus::LOCKED) return; + + DCHECK(!info_button_md_); + tri_view()->SetContainerVisible(TriView::Container::END, true); + + info_button_md_ = new SystemMenuButton( + this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuInfoIcon, + IDS_ASH_STATUS_TRAY_NETWORK_INFO); + tri_view()->AddView(TriView::Container::END, info_button_md_); + + if (login_ != LoginStatus::NOT_LOGGED_IN) { + DCHECK(!settings_button_md_); + settings_button_md_ = new SystemMenuButton( + this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuSettingsIcon, + IDS_ASH_STATUS_TRAY_NETWORK_SETTINGS); + + // Allow the user to access settings only if user is logged in + // and showing settings is allowed. There are situations (supervised user + // creation flow) when session is started but UI flow continues within + // login UI, i.e., no browser window is yet avaialable. + if (!WmShell::Get()->system_tray_delegate()->ShouldShowSettings()) + settings_button_md_->SetEnabled(false); + + tri_view()->AddView(TriView::Container::END, settings_button_md_); + } else { + proxy_settings_button_md_ = new SystemMenuButton( + this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuSettingsIcon, + IDS_ASH_STATUS_TRAY_NETWORK_PROXY_SETTINGS); + tri_view()->AddView(TriView::Container::END, proxy_settings_button_md_); } - - if (list_type_ != LIST_TYPE_VPN) { - NetworkStateHandler* network_state_handler = - NetworkHandler::Get()->network_state_handler(); - button_wifi_ = new TrayPopupHeaderButton( - this, IDR_AURA_UBER_TRAY_WIFI_ENABLED, IDR_AURA_UBER_TRAY_WIFI_DISABLED, - IDR_AURA_UBER_TRAY_WIFI_ENABLED_HOVER, - IDR_AURA_UBER_TRAY_WIFI_DISABLED_HOVER, IDS_ASH_STATUS_TRAY_WIFI); - button_wifi_->SetTooltipText( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISABLE_WIFI)); - button_wifi_->SetToggledTooltipText( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ENABLE_WIFI)); - title_row()->AddViewToRowNonMd(button_wifi_, true); - if (network_state_handler->IsTechnologyProhibited( - NetworkTypePattern::WiFi())) { - button_wifi_->SetEnabled(false); - button_wifi_->SetToggledTooltipText(l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_NETWORK_TECHNOLOGY_ENFORCED_BY_POLICY)); - } - - button_mobile_ = - new TrayPopupHeaderButton(this, IDR_AURA_UBER_TRAY_CELLULAR_ENABLED, - IDR_AURA_UBER_TRAY_CELLULAR_DISABLED, - IDR_AURA_UBER_TRAY_CELLULAR_ENABLED_HOVER, - IDR_AURA_UBER_TRAY_CELLULAR_DISABLED_HOVER, - IDS_ASH_STATUS_TRAY_CELLULAR); - button_mobile_->SetTooltipText( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISABLE_MOBILE)); - button_mobile_->SetToggledTooltipText( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ENABLE_MOBILE)); - if (network_state_handler->IsTechnologyProhibited( - NetworkTypePattern::Cellular())) { - button_mobile_->SetEnabled(false); - button_mobile_->SetToggledTooltipText(l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_NETWORK_TECHNOLOGY_ENFORCED_BY_POLICY)); - } - title_row()->AddViewToRowNonMd(button_mobile_, true); - } - - views::View* info_throbber_container = new views::View(); - InfoThrobberLayout* info_throbber_layout = new InfoThrobberLayout; - info_throbber_container->SetLayoutManager(info_throbber_layout); - title_row()->AddViewToRowNonMd(info_throbber_container, true); - - if (list_type_ != LIST_TYPE_VPN) { - // Place the throbber behind the info icon so that the icon receives - // click / touch events. The info icon is hidden when the throbber is - // active. - scanning_throbber_ = new ScanningThrobber(); - info_throbber_container->AddChildView(scanning_throbber_); - } - - info_icon_ = new InfoIcon(this); - info_icon_->SetFocusBehavior(FocusBehavior::ALWAYS); - info_icon_->SetTooltipText( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_INFO)); - info_throbber_container->AddChildView(info_icon_); } void NetworkStateListDetailedView::ShowSettings() { @@ -603,96 +468,6 @@ void NetworkStateListDetailedView::CreateNetworkExtra() { DCHECK(!UseMd()); - if (login_ == LoginStatus::LOCKED) - return; - - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - - views::View* bottom_row = new views::View(); - views::BoxLayout* layout = new views::BoxLayout( - views::BoxLayout::kHorizontal, kTrayMenuBottomRowPadding, - kTrayMenuBottomRowPadding, kTrayMenuBottomRowPaddingBetweenItems); - layout->SetDefaultFlex(1); - bottom_row->SetLayoutManager(layout); - - if (list_type_ != LIST_TYPE_VPN) { - other_wifi_ = new TrayPopupLabelButton( - this, rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_OTHER_WIFI)); - bottom_row->AddChildView(other_wifi_); - if (PolicyProhibitsUnmanaged()) { - other_wifi_->SetEnabled(false); - other_wifi_->SetTooltipText(l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_NETWORK_PROHIBITED_OTHER)); - } - - turn_on_wifi_ = new TrayPopupLabelButton( - this, rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_TURN_ON_WIFI)); - if (NetworkHandler::Get()->network_state_handler()->IsTechnologyProhibited( - NetworkTypePattern::WiFi())) { - turn_on_wifi_->SetEnabled(false); - turn_on_wifi_->SetTooltipText(l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_NETWORK_TECHNOLOGY_ENFORCED_BY_POLICY)); - } - bottom_row->AddChildView(turn_on_wifi_); - - other_mobile_ = new TrayPopupLabelButton( - this, rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_OTHER_MOBILE)); - bottom_row->AddChildView(other_mobile_); - } - - CreateSettingsEntry(); - - // Both settings_ and proxy_settings_ can be null. This happens when - // we're logged in but showing settings page is not enabled. - // Example: supervised user creation flow where user session is active - // but all action happens on the login window. - // Allowing opening proxy settigns dialog will break assumption in - // SystemTrayDelegateChromeOS::ChangeProxySettings(), see CHECK. - if (settings_ || proxy_settings_) - bottom_row->AddChildView(settings_ ? settings_ : proxy_settings_); - - AddChildView(bottom_row); -} - -void NetworkStateListDetailedView::UpdateHeaderButtons() { - NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); - if (button_wifi_) - UpdateTechnologyButton(button_wifi_, NetworkTypePattern::WiFi()); - if (button_mobile_) - UpdateTechnologyButton(button_mobile_, NetworkTypePattern::Mobile()); - if (proxy_settings_) - proxy_settings_->SetEnabled(handler->DefaultNetwork() != nullptr); - - if (list_type_ != LIST_TYPE_VPN && !UseMd()) { - // Update Wifi Scanning throbber. - bool scanning = - NetworkHandler::Get()->network_state_handler()->GetScanningByType( - NetworkTypePattern::WiFi()); - if (scanning != prev_wifi_scanning_state_) { - prev_wifi_scanning_state_ = scanning; - if (scanning) { - SetScanningStateForThrobberView(true); - - // Start animation on the |scanning_throbber_| indicator. - scanning_throbber_->Start(); - - // Since the |scanning_throbber_| view is behind the |info_icon_| - // view, the tooltip text for |info_icon_| will be used for both. - info_icon_->SetTooltipText(l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_WIFI_SCANNING_MESSAGE)); - } else { - SetScanningStateForThrobberView(false); - - // Stop animation on the |scanning_throbber_| indicator. - scanning_throbber_->Stop(); - info_icon_->SetTooltipText( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_INFO)); - } - } - } - - if (!UseMd()) - static_cast<views::View*>(title_row())->Layout(); } void NetworkStateListDetailedView::SetScanningStateForThrobberView( @@ -761,83 +536,8 @@ return false; } -void NetworkStateListDetailedView::UpdateNetworkExtra() { - if (login_ == LoginStatus::LOCKED) - return; - - View* layout_parent = nullptr; // All these buttons have the same parent. - NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); - if (other_wifi_) { - DCHECK(turn_on_wifi_); - NetworkStateHandler::TechnologyState state = - handler->GetTechnologyState(NetworkTypePattern::WiFi()); - if (state == NetworkStateHandler::TECHNOLOGY_UNAVAILABLE) { - turn_on_wifi_->SetVisible(false); - other_wifi_->SetVisible(false); - } else { - if (state == NetworkStateHandler::TECHNOLOGY_AVAILABLE) { - turn_on_wifi_->SetVisible(true); - turn_on_wifi_->SetEnabled(true); - other_wifi_->SetVisible(false); - } else if (state == NetworkStateHandler::TECHNOLOGY_ENABLED) { - turn_on_wifi_->SetVisible(false); - other_wifi_->SetVisible(true); - } else { - // Initializing or Enabling - turn_on_wifi_->SetVisible(true); - turn_on_wifi_->SetEnabled(false); - other_wifi_->SetVisible(false); - } - } - layout_parent = other_wifi_->parent(); - } - - if (other_mobile_) { - bool show_other_mobile = false; - NetworkStateHandler::TechnologyState state = - handler->GetTechnologyState(NetworkTypePattern::Mobile()); - if (state != NetworkStateHandler::TECHNOLOGY_UNAVAILABLE) { - const chromeos::DeviceState* device = - handler->GetDeviceStateByType(NetworkTypePattern::Mobile()); - show_other_mobile = (device && device->support_network_scan()); - } - if (show_other_mobile) { - other_mobile_->SetVisible(true); - other_mobile_->SetEnabled(state == - NetworkStateHandler::TECHNOLOGY_ENABLED); - } else { - other_mobile_->SetVisible(false); - } - if (!layout_parent) - layout_parent = other_wifi_->parent(); - } - - if (layout_parent) - layout_parent->Layout(); -} - void NetworkStateListDetailedView::CreateSettingsEntry() { DCHECK(!UseMd()); - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - bool show_settings = - WmShell::Get()->system_tray_delegate()->ShouldShowSettings(); - if (login_ != LoginStatus::NOT_LOGGED_IN) { - // Allow user access settings only if user is logged in - // and showing settings is allowed. There're situations (supervised user - // creation flow) when session is started but UI flow continues within - // login UI i.e. no browser window is yet avaialable. - if (show_settings) { - settings_ = new TrayPopupLabelButton( - this, rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_NETWORK_SETTINGS)); - if (list_type_ == LIST_TYPE_VPN) - settings_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - } - } else { - // Allow users to change proxy settings only when not logged in. - proxy_settings_ = new TrayPopupLabelButton( - this, - rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_NETWORK_PROXY_SETTINGS)); - } } void NetworkStateListDetailedView::ToggleInfoBubble() {
diff --git a/ash/common/system/chromeos/network/network_state_list_detailed_view.h b/ash/common/system/chromeos/network/network_state_list_detailed_view.h index 093d73a..f9e9b08f 100644 --- a/ash/common/system/chromeos/network/network_state_list_detailed_view.h +++ b/ash/common/system/chromeos/network/network_state_list_detailed_view.h
@@ -34,7 +34,6 @@ class SystemTrayItem; class ThrobberView; class TrayPopupHeaderButton; -class TrayPopupLabelButton; namespace tray { @@ -72,7 +71,6 @@ void CreateNetworkExtra(); // Update UI components. - void UpdateHeaderButtons(); void UpdateTechnologyButton(TrayPopupHeaderButton* button, const chromeos::NetworkTypePattern& technology); @@ -80,8 +78,6 @@ bool OrderChild(views::View* view, int index); - void UpdateNetworkExtra(); - // Adds a settings entry when logged in, and an entry for changing proxy // settings otherwise. void CreateSettingsEntry(); @@ -134,18 +130,6 @@ // Not used for material design. views::ImageButton* info_icon_; - // Not used for material design. - TrayPopupHeaderButton* button_wifi_; - - // Not used for material design. - TrayPopupHeaderButton* button_mobile_; - - TrayPopupLabelButton* other_wifi_; - TrayPopupLabelButton* turn_on_wifi_; - TrayPopupLabelButton* other_mobile_; - TrayPopupLabelButton* settings_; - TrayPopupLabelButton* proxy_settings_; - // Only used in material design. views::CustomButton* info_button_md_; views::CustomButton* settings_button_md_;
diff --git a/ash/common/system/chromeos/network/tray_sms.cc b/ash/common/system/chromeos/network/tray_sms.cc index a668863..4fedb7e 100644 --- a/ash/common/system/chromeos/network/tray_sms.cc +++ b/ash/common/system/chromeos/network/tray_sms.cc
@@ -8,7 +8,6 @@ #include "ash/common/material_design/material_design_controller.h" #include "ash/common/metrics/user_metrics_action.h" -#include "ash/common/system/tray/fixed_sized_scroll_view.h" #include "ash/common/system/tray/system_tray.h" #include "ash/common/system/tray/system_tray_bubble.h" #include "ash/common/system/tray/tray_constants.h" @@ -31,6 +30,7 @@ #include "ui/views/bubble/tray_bubble_view.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" +#include "ui/views/controls/scroll_view.h" #include "ui/views/layout/box_layout.h" #include "ui/views/layout/fill_layout.h" #include "ui/views/layout/grid_layout.h"
diff --git a/ash/common/system/chromeos/network/tray_vpn.cc b/ash/common/system/chromeos/network/tray_vpn.cc index cf4ce22e..d24684e 100644 --- a/ash/common/system/chromeos/network/tray_vpn.cc +++ b/ash/common/system/chromeos/network/tray_vpn.cc
@@ -16,7 +16,6 @@ #include "ash/common/system/tray/tray_constants.h" #include "ash/common/system/tray/tray_item_more.h" #include "ash/common/system/tray/tray_popup_item_style.h" -#include "ash/common/system/tray/tray_popup_label_button.h" #include "ash/common/wm_shell.h" #include "ash/resources/vector_icons/vector_icons.h" #include "chromeos/network/network_state.h"
diff --git a/ash/common/system/chromeos/network/vpn_list_view.cc b/ash/common/system/chromeos/network/vpn_list_view.cc index f4a21d2..39c4eaa 100644 --- a/ash/common/system/chromeos/network/vpn_list_view.cc +++ b/ash/common/system/chromeos/network/vpn_list_view.cc
@@ -20,7 +20,6 @@ #include "ash/common/system/tray/system_tray_controller.h" #include "ash/common/system/tray/throbber_view.h" #include "ash/common/system/tray/tray_constants.h" -#include "ash/common/system/tray/tray_popup_label_button.h" #include "ash/common/system/tray/tray_popup_utils.h" #include "ash/common/system/tray/tri_view.h" #include "ash/common/wm_shell.h" @@ -44,6 +43,7 @@ #include "ui/gfx/text_constants.h" #include "ui/views/border.h" #include "ui/views/controls/button/button.h" +#include "ui/views/controls/button/label_button.h" #include "ui/views/controls/label.h" #include "ui/views/controls/separator.h" #include "ui/views/layout/box_layout.h" @@ -58,13 +58,6 @@ return MaterialDesignController::IsSystemTrayMenuMaterial(); } -bool IsConnectedOrConnecting(const chromeos::NetworkState* network) { - return network->IsConnectedState() || network->IsConnectingState(); -} - -void IgnoreDisconnectError(const std::string& error_name, - std::unique_ptr<base::DictionaryValue> error_data) {} - // Indicates whether |network| belongs to this VPN provider. bool VpnProviderMatchesNetwork(const VPNProvider& provider, const chromeos::NetworkState& network) { @@ -163,28 +156,7 @@ // network_icon::AnimationObserver: void NetworkIconChanged() override; - // Overriden from ActionableView. - void ButtonPressed(views::Button* sender, const ui::Event& event) override; - private: - // A disconnect button that will be shown if the network is currently - // connected. Updates the list entry's hover state as the mouse enters/exits - // the button. - class DisconnectButton : public TrayPopupLabelButton { - public: - explicit DisconnectButton(VPNListNetworkEntry* parent); - - private: - // TrayPopupLabelButton: - void OnMouseEntered(const ui::MouseEvent& event) override; - void OnMouseExited(const ui::MouseEvent& event) override; - void OnBoundsChanged(const gfx::Rect& previous_bounds) override; - - VPNListNetworkEntry* parent_; - - DISALLOW_COPY_AND_ASSIGN(DisconnectButton); - }; - void UpdateFromNetworkState(const chromeos::NetworkState* network); void SetupConnectedItemMd(const base::string16& text, const gfx::ImageSkia& image); @@ -220,53 +192,6 @@ service_path_)); } -void VPNListNetworkEntry::ButtonPressed(views::Button* sender, - const ui::Event& event) { - if (sender != disconnect_button_) { - ActionableView::ButtonPressed(sender, event); - return; - } - - WmShell::Get()->RecordUserMetricsAction( - UMA_STATUS_AREA_VPN_DISCONNECT_CLICKED); - chromeos::NetworkHandler::Get() - ->network_connection_handler() - ->DisconnectNetwork(service_path_, base::Bind(&base::DoNothing), - base::Bind(&IgnoreDisconnectError)); -} - -VPNListNetworkEntry::DisconnectButton::DisconnectButton( - VPNListNetworkEntry* parent) - : TrayPopupLabelButton( - parent, - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_VPN_DISCONNECT)), - parent_(parent) { - DCHECK(!UseMd()); - DCHECK(parent_); -} - -void VPNListNetworkEntry::DisconnectButton::OnMouseEntered( - const ui::MouseEvent& event) { - TrayPopupLabelButton::OnMouseEntered(event); - parent_->SetHoverHighlight(false); -} - -void VPNListNetworkEntry::DisconnectButton::OnMouseExited( - const ui::MouseEvent& event) { - TrayPopupLabelButton::OnMouseExited(event); - if (parent_->IsMouseHovered()) - parent_->SetHoverHighlight(true); -} - -void VPNListNetworkEntry::DisconnectButton::OnBoundsChanged( - const gfx::Rect& previous_bounds) { - TrayPopupLabelButton::OnBoundsChanged(previous_bounds); - if (IsMouseHovered()) { - SetState(STATE_HOVERED); - parent_->SetHoverHighlight(false); - } -} - void VPNListNetworkEntry::UpdateFromNetworkState( const chromeos::NetworkState* network) { if (network && network->IsConnectingState()) @@ -287,39 +212,21 @@ base::string16 label = network_icon::GetLabelForNetwork( network, UseMd() ? network_icon::ICON_TYPE_MENU_LIST : network_icon::ICON_TYPE_LIST); - if (UseMd()) { - if (network->IsConnectedState()) - SetupConnectedItemMd(label, image); - else if (network->IsConnectingState()) - SetupConnectingItemMd(label, image); - else - AddIconAndLabel(image, label, false); + if (network->IsConnectedState()) + SetupConnectedItemMd(label, image); + else if (network->IsConnectingState()) + SetupConnectingItemMd(label, image); + else + AddIconAndLabel(image, label, false); - if (network->IsConnectedState()) { - disconnect_button_ = TrayPopupUtils::CreateTrayPopupButton( - this, l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_VPN_DISCONNECT)); - tri_view()->AddView(TriView::Container::END, disconnect_button_); - tri_view()->SetContainerVisible(TriView::Container::END, true); - tri_view()->SetContainerBorder( - TriView::Container::END, - views::CreateEmptyBorder(0, 0, 0, kTrayPopupButtonEndMargin)); - } - } else { - AddIconAndLabel(image, label, IsConnectedOrConnecting(network)); - if (IsConnectedOrConnecting(network)) { - disconnect_button_ = new DisconnectButton(this); - AddChildView(disconnect_button_); - SetBorder(views::CreateEmptyBorder(0, kTrayPopupPaddingHorizontal, 0, 3)); - } else { - SetBorder(views::CreateEmptyBorder(0, kTrayPopupPaddingHorizontal, 0, 0)); - } - // The icon and the disconnect button are always set to their preferred - // size. All remaining space is used for the network name. - views::BoxLayout* layout = new views::BoxLayout( - views::BoxLayout::kHorizontal, 0, 3, kTrayPopupPaddingBetweenItems); - SetLayoutManager(layout); - layout->SetDefaultFlex(0); - layout->SetFlexForView(text_label(), 1); + if (network->IsConnectedState()) { + disconnect_button_ = TrayPopupUtils::CreateTrayPopupButton( + this, l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_VPN_DISCONNECT)); + tri_view()->AddView(TriView::Container::END, disconnect_button_); + tri_view()->SetContainerVisible(TriView::Container::END, true); + tri_view()->SetContainerBorder( + TriView::Container::END, + views::CreateEmptyBorder(0, 0, 0, kTrayPopupButtonEndMargin)); } Layout(); }
diff --git a/ash/common/system/chromeos/palette/palette_tray.cc b/ash/common/system/chromeos/palette/palette_tray.cc index d2bccbee2..57790211 100644 --- a/ash/common/system/chromeos/palette/palette_tray.cc +++ b/ash/common/system/chromeos/palette/palette_tray.cc
@@ -29,6 +29,7 @@ #include "grit/ash_strings.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" +#include "ui/events/devices/input_device_manager.h" #include "ui/events/devices/stylus_state.h" #include "ui/gfx/color_palette.h" #include "ui/gfx/paint_vector_icon.h" @@ -156,9 +157,6 @@ : TrayBackgroundView(wm_shelf), palette_tool_manager_(new PaletteToolManager(this)), weak_factory_(this) { - // PaletteTray should only be instantiated if the palette feature is enabled. - DCHECK(IsPaletteFeatureEnabled()); - PaletteTool::RegisterToolInstances(palette_tool_manager_.get()); if (MaterialDesignController::IsShelfMaterial()) { @@ -177,17 +175,14 @@ WmShell::Get()->AddShellObserver(this); WmShell::Get()->GetSessionStateDelegate()->AddSessionStateObserver(this); - if (WmShell::Get()->palette_delegate()) { - WmShell::Get()->palette_delegate()->SetStylusStateChangedCallback( - base::Bind(&PaletteTray::OnStylusStateChanged, - weak_factory_.GetWeakPtr())); - } + ui::InputDeviceManager::GetInstance()->AddObserver(this); } PaletteTray::~PaletteTray() { if (bubble_) bubble_->bubble_view()->reset_delegate(); + ui::InputDeviceManager::GetInstance()->RemoveObserver(this); WmShell::Get()->RemoveShellObserver(this); WmShell::Get()->GetSessionStateDelegate()->RemoveSessionStateObserver(this); } @@ -293,6 +288,33 @@ HidePalette(); } +void PaletteTray::OnTouchscreenDeviceConfigurationChanged() { + UpdateIconVisibility(); +} + +void PaletteTray::OnStylusStateChanged(ui::StylusState stylus_state) { + PaletteDelegate* palette_delegate = WmShell::Get()->palette_delegate(); + + // Don't do anything if the palette should not be shown or if the user has + // disabled it all-together. + if (!IsInUserSession() || !palette_delegate->ShouldShowPalette()) + return; + + // Auto show/hide the palette if allowed by the user. + if (palette_delegate->ShouldAutoOpenPalette()) { + if (stylus_state == ui::StylusState::REMOVED && !bubble_) { + is_bubble_auto_opened_ = true; + ShowPalette(); + } else if (stylus_state == ui::StylusState::INSERTED && bubble_) { + HidePalette(); + } + } + + // Disable any active modes if the stylus has been inserted. + if (stylus_state == ui::StylusState::INSERTED) + palette_tool_manager_->DisableActiveTool(PaletteGroup::MODE); +} + void PaletteTray::BubbleViewDestroyed() { palette_tool_manager_->NotifyViewsDestroyed(); SetIsActive(false); @@ -385,12 +407,15 @@ } void PaletteTray::Initialize() { + PaletteDelegate* delegate = WmShell::Get()->palette_delegate(); + // |delegate| can be null in tests. + if (!delegate) + return; + // OnPaletteEnabledPrefChanged will get called with the initial pref value, // which will take care of showing the palette. - palette_enabled_subscription_ = - WmShell::Get()->palette_delegate()->AddPaletteEnableListener( - base::Bind(&PaletteTray::OnPaletteEnabledPrefChanged, - weak_factory_.GetWeakPtr())); + palette_enabled_subscription_ = delegate->AddPaletteEnableListener(base::Bind( + &PaletteTray::OnPaletteEnabledPrefChanged, weak_factory_.GetWeakPtr())); } void PaletteTray::SetIconBorderForShelfAlignment() { @@ -412,29 +437,6 @@ kTrayIconSize, kShelfIconColor)); } -void PaletteTray::OnStylusStateChanged(ui::StylusState stylus_state) { - PaletteDelegate* palette_delegate = WmShell::Get()->palette_delegate(); - - // Don't do anything if the palette should not be shown or if the user has - // disabled it all-together. - if (!IsInUserSession() || !palette_delegate->ShouldShowPalette()) - return; - - // Auto show/hide the palette if allowed by the user. - if (palette_delegate->ShouldAutoOpenPalette()) { - if (stylus_state == ui::StylusState::REMOVED && !bubble_) { - is_bubble_auto_opened_ = true; - ShowPalette(); - } else if (stylus_state == ui::StylusState::INSERTED && bubble_) { - HidePalette(); - } - } - - // Disable any active modes if the stylus has been inserted. - if (stylus_state == ui::StylusState::INSERTED) - palette_tool_manager_->DisableActiveTool(PaletteGroup::MODE); -} - void PaletteTray::OnPaletteEnabledPrefChanged(bool enabled) { is_palette_enabled_ = enabled; @@ -447,7 +449,8 @@ } void PaletteTray::UpdateIconVisibility() { - SetVisible(is_palette_enabled_ && IsInUserSession()); + SetVisible(is_palette_enabled_ && palette_utils::HasStylusInput() && + IsInUserSession()); } } // namespace ash
diff --git a/ash/common/system/chromeos/palette/palette_tray.h b/ash/common/system/chromeos/palette/palette_tray.h index 7dbc3c0..9633c35 100644 --- a/ash/common/system/chromeos/palette/palette_tray.h +++ b/ash/common/system/chromeos/palette/palette_tray.h
@@ -16,6 +16,7 @@ #include "ash/common/system/tray/tray_background_view.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "ui/events/devices/input_device_event_observer.h" namespace gfx { class Point; @@ -38,6 +39,7 @@ public SessionStateObserver, public ShellObserver, public PaletteToolManager::Delegate, + public ui::InputDeviceEventObserver, public views::TrayBubbleView::Delegate { public: explicit PaletteTray(WmShelf* wm_shelf); @@ -78,6 +80,10 @@ bool ContainsPointInScreen(const gfx::Point& point); private: + // ui::InputDeviceObserver: + void OnTouchscreenDeviceConfigurationChanged() override; + void OnStylusStateChanged(ui::StylusState stylus_state) override; + // views::TrayBubbleView::Delegate: void BubbleViewDestroyed() override; void OnMouseEnteredView() override; @@ -103,9 +109,6 @@ // Sets the icon to visible if the palette can be used. void UpdateIconVisibility(); - // Called when a stylus inserted or removed event is received. - void OnStylusStateChanged(ui::StylusState stylus_state); - // Called when the palette enabled pref has changed. void OnPaletteEnabledPrefChanged(bool enabled);
diff --git a/ash/common/system/chromeos/palette/palette_utils.cc b/ash/common/system/chromeos/palette/palette_utils.cc index 28f61d30..f32e40c 100644 --- a/ash/common/system/chromeos/palette/palette_utils.cc +++ b/ash/common/system/chromeos/palette/palette_utils.cc
@@ -11,13 +11,29 @@ #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "base/command_line.h" +#include "ui/events/devices/input_device_manager.h" +#include "ui/events/devices/touchscreen_device.h" #include "ui/gfx/geometry/point.h" namespace ash { +namespace palette_utils { -bool IsPaletteFeatureEnabled() { - return base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kAshEnablePalette); +bool HasStylusInput() { + // Allow the user to force-enable by passing a switch. + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kAshForceEnablePalette)) { + return true; + } + + for (const ui::TouchscreenDevice& device : + ui::InputDeviceManager::GetInstance()->GetTouchscreenDevices()) { + if (device.is_stylus && + device.type == ui::InputDeviceType::INPUT_DEVICE_INTERNAL) { + return true; + } + } + + return false; } bool IsPaletteEnabledOnEveryDisplay() { @@ -36,4 +52,5 @@ return false; } +} // namespace palette_utils } // namespace ash
diff --git a/ash/common/system/chromeos/palette/palette_utils.h b/ash/common/system/chromeos/palette/palette_utils.h index 06ee2ea..5f254814 100644 --- a/ash/common/system/chromeos/palette/palette_utils.h +++ b/ash/common/system/chromeos/palette/palette_utils.h
@@ -12,10 +12,12 @@ } namespace ash { +namespace palette_utils { -// Returns true if the palette feature is enabled. The palette itself may have -// been disabled by the user. -ASH_EXPORT bool IsPaletteFeatureEnabled(); +// Returns true if there is a stylus input device on the internal display. This +// will return false even if there is a stylus input device until hardware +// probing is complete (see ui::InputDeviceEventObserver). +ASH_EXPORT bool HasStylusInput(); // Returns true if the palette should be shown on every display. ASH_EXPORT bool IsPaletteEnabledOnEveryDisplay(); @@ -24,6 +26,7 @@ // given point (in screen space). ASH_EXPORT bool PaletteContainsPointInScreen(const gfx::Point& point); +} // namespace palette_utils } // namespace ash #endif // ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_PALETTE_UTILS_H_
diff --git a/ash/common/system/chromeos/screen_security/screen_tray_item.h b/ash/common/system/chromeos/screen_security/screen_tray_item.h index 66118f7..5ed992a 100644 --- a/ash/common/system/chromeos/screen_security/screen_tray_item.h +++ b/ash/common/system/chromeos/screen_security/screen_tray_item.h
@@ -11,7 +11,6 @@ #include "ash/common/system/tray/system_tray_item.h" #include "ash/common/system/tray/tray_item_view.h" #include "ash/common/system/tray/tray_notification_view.h" -#include "ash/common/system/tray/tray_popup_label_button.h" #include "base/macros.h" #include "ui/message_center/notification_delegate.h" #include "ui/views/controls/button/button.h"
diff --git a/ash/common/system/chromeos/session/logout_button_tray.cc b/ash/common/system/chromeos/session/logout_button_tray.cc index d86f6aa..8e8fafa 100644 --- a/ash/common/system/chromeos/session/logout_button_tray.cc +++ b/ash/common/system/chromeos/session/logout_button_tray.cc
@@ -7,7 +7,6 @@ #include <memory> #include <utility> -#include "ash/common/material_design/material_design_controller.h" #include "ash/common/shelf/wm_shelf_util.h" #include "ash/common/system/chromeos/session/logout_confirmation_controller.h" #include "ash/common/system/tray/system_tray_controller.h" @@ -33,99 +32,26 @@ #include "ui/views/painter.h" namespace ash { -namespace { - -const int kLogoutButtonHorizontalExtraPadding = 7; - -const int kLogoutButtonNormalImages[] = { - IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_TOP_LEFT, - IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_TOP, - IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_TOP_RIGHT, - IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_LEFT, - IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_CENTER, - IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_RIGHT, - IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_BOTTOM_LEFT, - IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_BOTTOM, - IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_BOTTOM_RIGHT}; - -const int kLogoutButtonPushedImages[] = { - IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_TOP_LEFT, - IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_TOP, - IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_TOP_RIGHT, - IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_LEFT, - IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_CENTER, - IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_RIGHT, - IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_BOTTOM_LEFT, - IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_BOTTOM, - IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_BOTTOM_RIGHT}; - -// TODO(estade): LogoutButton is not used in MD; remove it when possible. -// See crbug.com/614453 -class LogoutButton : public views::LabelButton { - public: - LogoutButton(views::ButtonListener* listener); - ~LogoutButton() override; - - private: - DISALLOW_COPY_AND_ASSIGN(LogoutButton); -}; - -} // namespace - -LogoutButton::LogoutButton(views::ButtonListener* listener) - : views::LabelButton(listener, base::string16()) { - SetupLabelForTray(label()); - SetFontList(label()->font_list()); - SetEnabledTextColors(SK_ColorWHITE); - - std::unique_ptr<views::LabelButtonAssetBorder> border( - new views::LabelButtonAssetBorder(views::Button::STYLE_TEXTBUTTON)); - border->SetPainter( - false, views::Button::STATE_NORMAL, - views::Painter::CreateImageGridPainter(kLogoutButtonNormalImages)); - border->SetPainter( - false, views::Button::STATE_HOVERED, - views::Painter::CreateImageGridPainter(kLogoutButtonNormalImages)); - border->SetPainter( - false, views::Button::STATE_PRESSED, - views::Painter::CreateImageGridPainter(kLogoutButtonPushedImages)); - gfx::Insets insets = border->GetInsets(); - insets += gfx::Insets(0, kLogoutButtonHorizontalExtraPadding, 0, - kLogoutButtonHorizontalExtraPadding); - border->set_insets(insets); - SetBorder(std::move(border)); - set_animate_on_state_change(false); - - SetMinSize(gfx::Size(0, GetTrayConstant(TRAY_ITEM_HEIGHT_LEGACY))); -} - -LogoutButton::~LogoutButton() {} LogoutButtonTray::LogoutButtonTray(WmShelf* wm_shelf) : TrayBackgroundView(wm_shelf), button_(nullptr), login_status_(LoginStatus::NOT_LOGGED_IN), show_logout_button_in_tray_(false) { - if (MaterialDesignController::IsShelfMaterial()) { - views::MdTextButton* button = - views::MdTextButton::Create(this, base::string16()); - button->SetProminent(true); - button->SetBgColorOverride(gfx::kGoogleRed700); - // Base font size + 2 = 14. - // TODO(estade): should this 2 be shared with other tray views? See - // crbug.com/623987 - button->AdjustFontSize(2); - button_ = button; + views::MdTextButton* button = + views::MdTextButton::Create(this, base::string16()); + button->SetProminent(true); + button->SetBgColorOverride(gfx::kGoogleRed700); + // Base font size + 2 = 14. + // TODO(estade): should this 2 be shared with other tray views? See + // crbug.com/623987 + button->AdjustFontSize(2); + button_ = button; - // Since |logout_button_tray| has a red background and it is distinguished - // by itself, no separator is needed on its right side. - set_separator_visibility(false); - } else { - button_ = new LogoutButton(this); - } + // Since |logout_button_tray| has a red background and it is distinguished + // by itself, no separator is needed on its right side. + set_separator_visibility(false); tray_container()->AddChildView(button_); - if (!MaterialDesignController::IsShelfMaterial()) - tray_container()->SetBorder(views::NullBorder()); WmShell::Get()->system_tray_notifier()->AddLogoutButtonObserver(this); } @@ -138,8 +64,6 @@ // TrayBackgroundView::SetShelfAlignment() can lay it out correctly. UpdateButtonTextAndImage(login_status_, alignment); TrayBackgroundView::SetShelfAlignment(alignment); - if (!MaterialDesignController::IsShelfMaterial()) - tray_container()->SetBorder(views::NullBorder()); } base::string16 LogoutButtonTray::GetAccessibleNameForTray() { @@ -191,19 +115,16 @@ login_status_ = login_status; const base::string16 title = user::GetLocalizedSignOutStringForStatus(login_status, false); - const int button_size = MaterialDesignController::IsShelfMaterial() - ? kTrayItemSize - : GetTrayConstant(TRAY_ITEM_HEIGHT_LEGACY); if (IsHorizontalAlignment(alignment)) { button_->SetText(title); button_->SetImage(views::LabelButton::STATE_NORMAL, gfx::ImageSkia()); - button_->SetMinSize(gfx::Size(0, button_size)); + button_->SetMinSize(gfx::Size(0, kTrayItemSize)); } else { button_->SetText(base::string16()); button_->SetAccessibleName(title); button_->SetImage(views::LabelButton::STATE_NORMAL, gfx::CreateVectorIcon(kShelfLogoutIcon, kTrayIconColor)); - button_->SetMinSize(gfx::Size(button_size, button_size)); + button_->SetMinSize(gfx::Size(kTrayItemSize, kTrayItemSize)); } UpdateVisibility(); }
diff --git a/ash/common/system/ime/tray_ime_chromeos.cc b/ash/common/system/ime/tray_ime_chromeos.cc index 2b12d92..5a23a9d8 100644 --- a/ash/common/system/ime/tray_ime_chromeos.cc +++ b/ash/common/system/ime/tray_ime_chromeos.cc
@@ -8,7 +8,6 @@ #include "ash/common/material_design/material_design_controller.h" #include "ash/common/session/session_state_delegate.h" -#include "ash/common/system/chromeos/ime_menu/ime_list_view.h" #include "ash/common/system/tray/hover_highlight_view.h" #include "ash/common/system/tray/system_tray.h" #include "ash/common/system/tray/system_tray_controller.h" @@ -31,11 +30,13 @@ #include "grit/ash_strings.h" #include "ui/accessibility/ax_enums.h" #include "ui/accessibility/ax_node_data.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/font.h" #include "ui/gfx/image/image.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/keyboard/keyboard_util.h" +#include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" #include "ui/views/layout/box_layout.h" #include "ui/views/widget/widget.h" @@ -119,6 +120,10 @@ ~IMEDetailedView() override {} + void SetImeManagedMessage(base::string16 ime_managed_message) { + ime_managed_message_ = ime_managed_message; + } + void Update(const IMEInfoList& list, const IMEPropertyInfoList& property_list, bool show_keyboard_toggle, @@ -144,6 +149,7 @@ void ResetImeListView() override { ImeListView::ResetImeListView(); settings_button_ = nullptr; + controlled_setting_icon_ = nullptr; } void HandleButtonPressed(views::Button* sender, @@ -155,6 +161,14 @@ void CreateExtraTitleRowButtons() override { if (MaterialDesignController::IsSystemTrayMenuMaterial()) { + if (!ime_managed_message_.empty()) { + controlled_setting_icon_ = TrayPopupUtils::CreateMainImageView(); + controlled_setting_icon_->SetImage( + gfx::CreateVectorIcon(kSystemMenuBusinessIcon, kMenuIconColor)); + controlled_setting_icon_->SetTooltipText(ime_managed_message_); + tri_view()->AddView(TriView::Container::END, controlled_setting_icon_); + } + tri_view()->SetContainerVisible(TriView::Container::END, true); settings_button_ = CreateSettingsButton(login_); tri_view()->AddView(TriView::Container::END, settings_button_); @@ -186,6 +200,12 @@ // Only used in material design. views::Button* settings_button_; + // This icon says that the IMEs are managed by policy. + views::ImageView* controlled_setting_icon_; + // If non-empty, a controlled setting icon should be displayed with this + // string as tooltip. + base::string16 ime_managed_message_; + DISALLOW_COPY_AND_ASSIGN(IMEDetailedView); }; @@ -227,14 +247,16 @@ default_->SetVisible(ShouldDefaultViewBeVisible()); default_->UpdateLabel(GetDefaultViewLabel(ime_list_.size() > 1)); } - if (detailed_) + if (detailed_) { + detailed_->SetImeManagedMessage(ime_managed_message_); detailed_->Update(ime_list_, property_list_, ShouldShowKeyboardToggle(), - ImeListView::HIDE_SINGLE_IME); + GetSingleImeBehavior()); + } } void TrayIME::UpdateTrayLabel(const IMEInfo& current, size_t count) { if (tray_label_) { - bool visible = count > 1 && is_visible_; + bool visible = ShouldShowImeTrayItem(count) && is_visible_; tray_label_->SetVisible(visible); // Do not change label before hiding because this change is noticeable. if (!visible) @@ -282,8 +304,8 @@ views::View* TrayIME::CreateDefaultView(LoginStatus status) { CHECK(default_ == NULL); - default_ = - new tray::IMEDefaultView(this, GetDefaultViewLabel(ime_list_.size() > 1)); + default_ = new tray::IMEDefaultView( + this, GetDefaultViewLabel(ShouldShowImeTrayItem(ime_list_.size()))); default_->SetVisible(ShouldDefaultViewBeVisible()); return default_; } @@ -291,7 +313,8 @@ views::View* TrayIME::CreateDetailedView(LoginStatus status) { CHECK(detailed_ == NULL); detailed_ = new tray::IMEDetailedView(this, status); - detailed_->Init(ShouldShowKeyboardToggle(), ImeListView::HIDE_SINGLE_IME); + detailed_->SetImeManagedMessage(ime_managed_message_); + detailed_->Init(ShouldShowKeyboardToggle(), GetSingleImeBehavior()); return detailed_; } @@ -322,6 +345,7 @@ delegate->GetCurrentIME(¤t_ime_); delegate->GetAvailableIMEList(&ime_list_); delegate->GetCurrentIMEProperties(&property_list_); + ime_managed_message_ = delegate->GetIMEManagedMessage(); Update(); } @@ -334,9 +358,27 @@ Update(); } +bool TrayIME::IsIMEManaged() { + return !ime_managed_message_.empty(); +} + bool TrayIME::ShouldDefaultViewBeVisible() { - return is_visible_ && (ime_list_.size() > 1 || property_list_.size() > 1 || - ShouldShowKeyboardToggle()); + return is_visible_ && + (ShouldShowImeTrayItem(ime_list_.size()) || + property_list_.size() > 1 || ShouldShowKeyboardToggle()); +} + +bool TrayIME::ShouldShowImeTrayItem(size_t ime_count) { + // If managed, we want to show the tray icon even if there's only one input + // method to choose from. + size_t threshold = IsIMEManaged() ? 1 : 2; + return ime_count >= threshold; +} + +ImeListView::SingleImeBehavior TrayIME::GetSingleImeBehavior() { + // If managed, we also want to show a single IME. + return IsIMEManaged() ? ImeListView::SHOW_SINGLE_IME + : ImeListView::HIDE_SINGLE_IME; } } // namespace ash
diff --git a/ash/common/system/ime/tray_ime_chromeos.h b/ash/common/system/ime/tray_ime_chromeos.h index b04942d..bce373e 100644 --- a/ash/common/system/ime/tray_ime_chromeos.h +++ b/ash/common/system/ime/tray_ime_chromeos.h
@@ -8,6 +8,7 @@ #include <stddef.h> #include "ash/common/system/accessibility_observer.h" +#include "ash/common/system/chromeos/ime_menu/ime_list_view.h" #include "ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_observer.h" #include "ash/common/system/ime/ime_observer.h" #include "ash/common/system/tray/ime_info.h" @@ -65,9 +66,18 @@ void OnIMERefresh() override; void OnIMEMenuActivationChanged(bool is_active) override; + // Returns true input methods are managed by policy. + bool IsIMEManaged(); + // Whether the default view should be shown. bool ShouldDefaultViewBeVisible(); + // Decides if a tray icon should be shown. + bool ShouldShowImeTrayItem(size_t ime_count); + // Mandates behavior for the single IME case for the detailed IME list + // sub-view. + ImeListView::SingleImeBehavior GetSingleImeBehavior(); + TrayItemView* tray_label_; tray::IMEDefaultView* default_; tray::IMEDetailedView* detailed_; @@ -77,6 +87,10 @@ IMEInfoList ime_list_; IMEInfo current_ime_; IMEPropertyInfoList property_list_; + // If non-empty, a controlled-setting icon should be displayed with a tooltip + // text defined by this string. + base::string16 ime_managed_message_; + // Whether the IME label and tray items should be visible. bool is_visible_;
diff --git a/ash/common/system/ime/tray_ime_chromeos_unittest.cc b/ash/common/system/ime/tray_ime_chromeos_unittest.cc index b71f2f05..c90fa49 100644 --- a/ash/common/system/ime/tray_ime_chromeos_unittest.cc +++ b/ash/common/system/ime/tray_ime_chromeos_unittest.cc
@@ -6,11 +6,11 @@ #include "ash/common/accessibility_delegate.h" #include "ash/common/accessibility_types.h" +#include "ash/common/system/chromeos/ime_menu/ime_list_view.h" #include "ash/common/system/tray/system_tray_notifier.h" -#include "ash/common/system/tray/tray_details_view.h" #include "ash/common/wm_shell.h" #include "ash/test/ash_test_base.h" -#include "base/command_line.h" +#include "base/strings/utf_string_conversions.h" #include "ui/events/devices/device_data_manager.h" #include "ui/keyboard/keyboard_util.h" @@ -21,11 +21,9 @@ TrayIMETest() {} ~TrayIMETest() override {} - TrayIME* tray() { return tray_.get(); } + views::View* default_view() const { return default_view_.get(); } - views::View* default_view() { return default_view_.get(); } - - views::View* detailed_view() { return detailed_view_.get(); } + views::View* detailed_view() const { return detailed_view_.get(); } // Mocks enabling the a11y virtual keyboard since the actual a11y manager // is not created in ash tests. @@ -34,9 +32,12 @@ // Sets the current number of active IMEs. void SetIMELength(int length); - // Returns the view in the detailed views scroll content at the provided - // index. - views::View* GetScrollChildView(int index); + // Returns the view responsible for toggling virtual keyboard. + views::View* GetToggleView() const; + + // Sets the managed IMEs tooltip message (and thus also if IMEs are managed = + // non-empty or not = empty) + void SetManagedMessage(base::string16 managed_message); void SuppressKeyboard(); void RestoreKeyboard(); @@ -75,12 +76,14 @@ tray_->Update(); } -views::View* TrayIMETest::GetScrollChildView(int index) { - TrayDetailsView* details = static_cast<TrayDetailsView*>(detailed_view()); - views::View* content = details->scroll_content(); - EXPECT_TRUE(content); - EXPECT_GT(content->child_count(), index); - return content->child_at(index); +views::View* TrayIMETest::GetToggleView() const { + ImeListViewTestApi test_api(static_cast<ImeListView*>(detailed_view())); + return test_api.GetToggleView(); +} + +void TrayIMETest::SetManagedMessage(base::string16 managed_message) { + tray_->ime_managed_message_ = managed_message; + tray_->Update(); } void TrayIMETest::SuppressKeyboard() { @@ -133,9 +136,6 @@ // Tests that if the keyboard is not suppressed the default view is hidden // if less than 2 IMEs are present. TEST_F(TrayIMETest, HiddenWithNoIMEs) { - if (MaterialDesignController::IsSystemTrayMenuMaterial()) - return; - SetIMELength(0); EXPECT_FALSE(default_view()->visible()); SetIMELength(1); @@ -144,12 +144,21 @@ EXPECT_TRUE(default_view()->visible()); } +// Tests that if IMEs are managed, the default view is displayed even for a +// single IME. +TEST_F(TrayIMETest, ShownWithSingleIMEWhenManaged) { + SetManagedMessage(base::ASCIIToUTF16("managed")); + SetIMELength(0); + EXPECT_FALSE(default_view()->visible()); + SetIMELength(1); + EXPECT_TRUE(default_view()->visible()); + SetIMELength(2); + EXPECT_TRUE(default_view()->visible()); +} + // Tests that if no IMEs are present the default view is hidden when a11y is // enabled. TEST_F(TrayIMETest, HidesOnA11yEnabled) { - if (MaterialDesignController::IsSystemTrayMenuMaterial()) - return; - SetIMELength(0); SuppressKeyboard(); EXPECT_TRUE(default_view()->visible()); @@ -164,22 +173,19 @@ // Tests that clicking on the keyboard toggle causes the virtual keyboard // to toggle between enabled and disabled. TEST_F(TrayIMETest, PerformActionOnDetailedView) { - if (MaterialDesignController::IsSystemTrayMenuMaterial()) - return; - SetIMELength(0); SuppressKeyboard(); EXPECT_FALSE(keyboard::IsKeyboardEnabled()); - views::View* toggle = GetScrollChildView(0); + views::View* toggle = GetToggleView(); ui::GestureEvent tap(0, 0, 0, base::TimeTicks(), ui::GestureEventDetails(ui::ET_GESTURE_TAP)); // Enable the keyboard. toggle->OnGestureEvent(&tap); EXPECT_TRUE(keyboard::IsKeyboardEnabled()); EXPECT_TRUE(default_view()->visible()); - // With no IMEs the toggle should be the first child. - toggle = GetScrollChildView(0); + // Clicking again should disable the keyboard. + toggle = GetToggleView(); tap = ui::GestureEvent(0, 0, 0, base::TimeTicks(), ui::GestureEventDetails(ui::ET_GESTURE_TAP)); toggle->OnGestureEvent(&tap);
diff --git a/ash/common/system/status_area_widget.cc b/ash/common/system/status_area_widget.cc index 1fe17f6..afb1088 100644 --- a/ash/common/system/status_area_widget.cc +++ b/ash/common/system/status_area_widget.cc
@@ -210,16 +210,13 @@ } void StatusAreaWidget::AddPaletteTray() { - if (!IsPaletteFeatureEnabled()) - return; - const display::Display& display = WmLookup::Get()->GetWindowForWidget(this)->GetDisplayNearestWindow(); // Create the palette only on the internal display, where the stylus is // available. We also create a palette on every display if requested from the // command line. - if (display.IsInternal() || IsPaletteEnabledOnEveryDisplay()) { + if (display.IsInternal() || palette_utils::IsPaletteEnabledOnEveryDisplay()) { palette_tray_ = new PaletteTray(wm_shelf_); status_area_widget_delegate_->AddTray(palette_tray_); }
diff --git a/ash/common/system/toast/toast_overlay.cc b/ash/common/system/toast/toast_overlay.cc index 4e0da1d..97b620a 100644 --- a/ash/common/system/toast/toast_overlay.cc +++ b/ash/common/system/toast/toast_overlay.cc
@@ -184,10 +184,10 @@ ToastOverlayView::~ToastOverlayView() {} void ToastOverlayView::OnPaint(gfx::Canvas* canvas) { - cc::PaintFlags paint; - paint.setStyle(cc::PaintFlags::kFill_Style); - paint.setColor(kButtonBackgroundColor); - canvas->DrawRoundRect(GetLocalBounds(), 2, paint); + cc::PaintFlags flags; + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setColor(kButtonBackgroundColor); + canvas->DrawRoundRect(GetLocalBounds(), 2, flags); views::View::OnPaint(canvas); }
diff --git a/ash/common/system/tray/fixed_sized_scroll_view.cc b/ash/common/system/tray/fixed_sized_scroll_view.cc deleted file mode 100644 index 1959fd6..0000000 --- a/ash/common/system/tray/fixed_sized_scroll_view.cc +++ /dev/null
@@ -1,85 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/common/system/tray/fixed_sized_scroll_view.h" - -#include "ash/common/material_design/material_design_controller.h" - -namespace ash { - -namespace { - -bool UseMd() { - return MaterialDesignController::IsSystemTrayMenuMaterial(); -} - -} // namespace - -FixedSizedScrollView::FixedSizedScrollView() { - set_notify_enter_exit_on_child(true); -} - -FixedSizedScrollView::~FixedSizedScrollView() {} - -void FixedSizedScrollView::SetContentsView(views::View* view) { - SetContents(view); - if (!UseMd()) - view->SetBoundsRect(gfx::Rect(view->GetPreferredSize())); -} - -void FixedSizedScrollView::SetFixedSize(const gfx::Size& size) { - DCHECK(!UseMd()); - if (fixed_size_ == size) - return; - fixed_size_ = size; - PreferredSizeChanged(); -} - -void FixedSizedScrollView::set_fixed_size(const gfx::Size& size) { - DCHECK(!UseMd()); - fixed_size_ = size; -} - -gfx::Size FixedSizedScrollView::GetPreferredSize() const { - if (UseMd()) - return views::View::GetPreferredSize(); - - gfx::Size size = - fixed_size_.IsEmpty() ? contents()->GetPreferredSize() : fixed_size_; - gfx::Insets insets = GetInsets(); - size.Enlarge(insets.width(), insets.height()); - return size; -} - -void FixedSizedScrollView::Layout() { - if (UseMd()) - return views::ScrollView::Layout(); - - gfx::Rect bounds = gfx::Rect(contents()->GetPreferredSize()); - bounds.set_width(std::max(0, width() - GetScrollBarLayoutWidth())); - // Keep the origin of the contents unchanged so that the list will not scroll - // away from the current visible region user is viewing. ScrollView::Layout() - // will make sure the contents line up with its viewport properly if - // the contents moves out of the viewport region. - bounds.set_origin(contents()->origin()); - contents()->SetBoundsRect(bounds); - - views::ScrollView::Layout(); - if (!vertical_scroll_bar()->visible()) { - gfx::Rect bounds = contents()->bounds(); - bounds.set_width(bounds.width() + GetScrollBarLayoutWidth()); - contents()->SetBoundsRect(bounds); - } -} - -void FixedSizedScrollView::OnBoundsChanged(const gfx::Rect& previous_bounds) { - if (UseMd()) - return; - - gfx::Rect bounds = gfx::Rect(contents()->GetPreferredSize()); - bounds.set_width(std::max(0, width() - GetScrollBarLayoutWidth())); - contents()->SetBoundsRect(bounds); -} - -} // namespace ash
diff --git a/ash/common/system/tray/fixed_sized_scroll_view.h b/ash/common/system/tray/fixed_sized_scroll_view.h deleted file mode 100644 index d45c479f..0000000 --- a/ash/common/system/tray/fixed_sized_scroll_view.h +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_COMMON_SYSTEM_TRAY_FIXED_SIZED_SCROLL_VIEW_H_ -#define ASH_COMMON_SYSTEM_TRAY_FIXED_SIZED_SCROLL_VIEW_H_ - -#include "base/macros.h" -#include "ui/views/controls/scroll_view.h" - -namespace ash { - -// A custom scroll-view that has a specified dimension. -// TODO(estade): can we get rid of this class? In MD, it hardly differs in -// behavior from ScrollView. -class FixedSizedScrollView : public views::ScrollView { - public: - FixedSizedScrollView(); - ~FixedSizedScrollView() override; - - void SetContentsView(views::View* view); - - // Change the fixed size of the view. Invalidates the layout (by calling - // PreferredSizeChanged()). - void SetFixedSize(const gfx::Size& size); - - void set_fixed_size(const gfx::Size& size); - - // Overridden from views::View: - gfx::Size GetPreferredSize() const override; - void Layout() override; - - protected: - // Overridden from views::View: - void OnBoundsChanged(const gfx::Rect& previous_bounds) override; - - private: - gfx::Size fixed_size_; - - DISALLOW_COPY_AND_ASSIGN(FixedSizedScrollView); -}; - -} // namespace ash - -#endif // ASH_COMMON_SYSTEM_TRAY_FIXED_SIZED_SCROLL_VIEW_H_
diff --git a/ash/common/system/tray/system_menu_button.cc b/ash/common/system/tray/system_menu_button.cc index d9e04a22..d0cca16 100644 --- a/ash/common/system/tray/system_menu_button.cc +++ b/ash/common/system/tray/system_menu_button.cc
@@ -39,14 +39,8 @@ SetTooltipText(l10n_util::GetStringUTF16(accessible_name_id)); - SetFocusForPlatform(); - SetFocusPainter(views::Painter::CreateSolidFocusPainter( - kFocusBorderColor, kFocusBorderThickness, gfx::InsetsF())); - - SetInkDropMode(InkDropMode::ON); - set_has_ink_drop_action_on_click(true); - set_ink_drop_base_color(kTrayPopupInkDropBaseColor); - set_ink_drop_visible_opacity(kTrayPopupInkDropRippleOpacity); + SetFocusPainter(TrayPopupUtils::CreateFocusPainter()); + TrayPopupUtils::ConfigureTrayPopupButton(this); } SystemMenuButton::SystemMenuButton(views::ButtonListener* listener,
diff --git a/ash/common/system/tray/system_tray_delegate.cc b/ash/common/system/tray/system_tray_delegate.cc index e3ba5b9..3e250ba 100644 --- a/ash/common/system/tray/system_tray_delegate.cc +++ b/ash/common/system/tray/system_tray_delegate.cc
@@ -86,6 +86,10 @@ void SystemTrayDelegate::GetCurrentIMEProperties(IMEPropertyInfoList* list) {} +base::string16 SystemTrayDelegate::GetIMEManagedMessage() { + return base::string16(); +} + void SystemTrayDelegate::SwitchIME(const std::string& ime_id) {} void SystemTrayDelegate::ActivateIMEProperty(const std::string& key) {}
diff --git a/ash/common/system/tray/system_tray_delegate.h b/ash/common/system/tray/system_tray_delegate.h index 2c19d6d8..eb99683 100644 --- a/ash/common/system/tray/system_tray_delegate.h +++ b/ash/common/system/tray/system_tray_delegate.h
@@ -141,6 +141,9 @@ // Returns a list of properties for the currently selected IME. virtual void GetCurrentIMEProperties(IMEPropertyInfoList* list); + // Returns a non-empty string if IMEs are managed by policy. + virtual base::string16 GetIMEManagedMessage(); + // Switches to the selected input method. virtual void SwitchIME(const std::string& ime_id);
diff --git a/ash/common/system/tray/system_tray_unittest.cc b/ash/common/system/tray/system_tray_unittest.cc index 6f7854ef..0da4a4c 100644 --- a/ash/common/system/tray/system_tray_unittest.cc +++ b/ash/common/system/tray/system_tray_unittest.cc
@@ -9,7 +9,6 @@ #include "ash/common/accelerators/accelerator_controller.h" #include "ash/common/accessibility_delegate.h" -#include "ash/common/material_design/material_design_controller.h" #include "ash/common/shelf/wm_shelf.h" #include "ash/common/system/status_area_widget.h" #include "ash/common/system/tray/system_tray_bubble.h" @@ -538,15 +537,6 @@ test::kAccessibilityTrayItemViewId); ASSERT_TRUE(accessibility); EXPECT_TRUE(accessibility->visible()); - - // Settings row is not present in material design. - if (!MaterialDesignController::IsSystemTrayMenuMaterial()) { - const views::View* settings = - tray->GetSystemBubble()->bubble_view()->GetViewByID( - test::kSettingsTrayItemViewId); - ASSERT_TRUE(settings); - EXPECT_TRUE(settings->visible()); - } } // Tests that if SetVisible(true) is called while animating to hidden that the @@ -569,60 +559,6 @@ EXPECT_EQ(1.0f, tray->layer()->GetTargetOpacity()); } -// Tests that touch on an item in the system bubble triggers it to become -// active. -TEST_F(SystemTrayTest, TrayPopupItemContainerTouchFeedback) { - // Material design will use the ink drop ripple framework to show - // active states. - if (MaterialDesignController::IsSystemTrayMenuMaterial()) - return; - - SystemTray* tray = GetPrimarySystemTray(); - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - - TrayPopupItemContainer* view = static_cast<TrayPopupItemContainer*>( - tray->GetSystemBubble()->bubble_view()->child_at(0)); - EXPECT_FALSE(view->active()); - - ui::test::EventGenerator& generator = GetEventGenerator(); - generator.set_current_location(view->GetBoundsInScreen().CenterPoint()); - generator.PressTouch(); - EXPECT_TRUE(view->active()); - - generator.ReleaseTouch(); - EXPECT_FALSE(view->active()); -} - -// Tests that touch events on an item in the system bubble cause it to stop -// being active. -TEST_F(SystemTrayTest, TrayPopupItemContainerTouchFeedbackCancellation) { - // Material design will use the ink drop ripple framework to show - // active states. - if (MaterialDesignController::IsSystemTrayMenuMaterial()) - return; - - SystemTray* tray = GetPrimarySystemTray(); - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - - TrayPopupItemContainer* view = static_cast<TrayPopupItemContainer*>( - tray->GetSystemBubble()->bubble_view()->child_at(0)); - EXPECT_FALSE(view->active()); - - gfx::Rect view_bounds = view->GetBoundsInScreen(); - ui::test::EventGenerator& generator = GetEventGenerator(); - generator.set_current_location(view_bounds.CenterPoint()); - generator.PressTouch(); - EXPECT_TRUE(view->active()); - - gfx::Point move_point(view_bounds.x(), view_bounds.CenterPoint().y()); - generator.MoveTouch(move_point); - EXPECT_FALSE(view->active()); - - generator.set_current_location(move_point); - generator.ReleaseTouch(); - EXPECT_FALSE(view->active()); -} - TEST_F(SystemTrayTest, SystemTrayHeightWithBubble) { SystemTray* tray = GetPrimarySystemTray(); WebNotificationTray* notification_tray =
diff --git a/ash/common/system/tray/tray_background_view.cc b/ash/common/system/tray/tray_background_view.cc index e5aef5a4..bf3620b8 100644 --- a/ash/common/system/tray/tray_background_view.cc +++ b/ash/common/system/tray/tray_background_view.cc
@@ -127,20 +127,20 @@ WmShelf* GetShelf() const { return tray_background_view_->shelf(); } void PaintMaterial(gfx::Canvas* canvas, views::View* view) const { - cc::PaintFlags background_paint; - background_paint.setFlags(cc::PaintFlags::kAntiAlias_Flag); - background_paint.setColor(SkColorSetA(kShelfBaseColor, alpha_)); + cc::PaintFlags background_flags; + background_flags.setFlags(cc::PaintFlags::kAntiAlias_Flag); + background_flags.setColor(SkColorSetA(kShelfBaseColor, alpha_)); gfx::Insets insets = GetMirroredBackgroundInsets(GetShelf()->GetAlignment()); gfx::Rect bounds = view->GetLocalBounds(); bounds.Inset(insets); - canvas->DrawRoundRect(bounds, kTrayRoundedBorderRadius, background_paint); + canvas->DrawRoundRect(bounds, kTrayRoundedBorderRadius, background_flags); if (draws_active_ && tray_background_view_->is_active()) { - cc::PaintFlags highlight_paint; - highlight_paint.setFlags(cc::PaintFlags::kAntiAlias_Flag); - highlight_paint.setColor(kShelfButtonActivatedHighlightColor); - canvas->DrawRoundRect(bounds, kTrayRoundedBorderRadius, highlight_paint); + cc::PaintFlags highlight_flags; + highlight_flags.setFlags(cc::PaintFlags::kAntiAlias_Flag); + highlight_flags.setColor(kShelfButtonActivatedHighlightColor); + canvas->DrawRoundRect(bounds, kTrayRoundedBorderRadius, highlight_flags); } } @@ -600,9 +600,9 @@ const int y = (GetShelfConstant(SHELF_SIZE) - kTrayItemSize) / 2; gfx::ScopedCanvas scoped_canvas(canvas); const float scale = canvas->UndoDeviceScaleFactor(); - cc::PaintFlags paint; - paint.setColor(kSeparatorColor); - paint.setAntiAlias(true); + cc::PaintFlags flags; + flags.setColor(kSeparatorColor); + flags.setAntiAlias(true); const gfx::Rect bounds = horizontal_shelf ? gfx::Rect(x, y, kSeparatorWidth, height) @@ -616,7 +616,7 @@ (horizontal_shelf && base::i18n::IsRTL() ? rect.bottom_left() : rect.bottom_right()); - canvas->DrawLine(line_start, line_end, paint); + canvas->DrawLine(line_start, line_end, flags); } gfx::Insets TrayBackgroundView::GetBackgroundInsets() const {
diff --git a/ash/common/system/tray/tray_details_view.cc b/ash/common/system/tray/tray_details_view.cc index 1b1b6f9..b51ab37 100644 --- a/ash/common/system/tray/tray_details_view.cc +++ b/ash/common/system/tray/tray_details_view.cc
@@ -6,7 +6,6 @@ #include "ash/common/ash_view_ids.h" #include "ash/common/material_design/material_design_controller.h" -#include "ash/common/system/tray/fixed_sized_scroll_view.h" #include "ash/common/system/tray/system_menu_button.h" #include "ash/common/system/tray/system_tray.h" #include "ash/common/system/tray/system_tray_item.h" @@ -216,14 +215,14 @@ const gfx::Rect& shadowed_area) { ui::PaintRecorder recorder(context, size()); gfx::Canvas* canvas = recorder.canvas(); - cc::PaintFlags paint; + cc::PaintFlags flags; gfx::ShadowValues shadow; shadow.emplace_back(gfx::Vector2d(0, kShadowOffsetY), kShadowBlur, kSeparatorColor); - paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadow)); - paint.setAntiAlias(true); + flags.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadow)); + flags.setAntiAlias(true); canvas->ClipRect(shadowed_area, SkClipOp::kDifference); - canvas->DrawRect(shadowed_area, paint); + canvas->DrawRect(shadowed_area, flags); } views::BoxLayout* box_layout_; @@ -363,8 +362,8 @@ void TrayDetailsView::CreateScrollableList() { DCHECK(!scroller_); scroll_content_ = new ScrollContentsView(); - scroller_ = new FixedSizedScrollView; - scroller_->SetContentsView(scroll_content_); + scroller_ = new views::ScrollView; + scroller_->SetContents(scroll_content_); // Make the |scroller_| have a layer to clip |scroll_content_|'s children. // TODO(varkha): Make the sticky rows work with EnableViewPortLayer(). scroller_->SetPaintToLayer(); @@ -492,39 +491,9 @@ } void TrayDetailsView::Layout() { - if (UseMd()) { - views::View::Layout(); - if (scroller_ && !scroller_->is_bounded()) - scroller_->ClipHeightTo(0, scroller_->height()); - return; - } - - if (bounds().IsEmpty()) { - views::View::Layout(); - return; - } - - if (scroller_) { - scroller_->set_fixed_size(gfx::Size()); - gfx::Size size = GetPreferredSize(); - - // Set the scroller to fill the space above the bottom row, so that the - // bottom row of the detailed view will always stay just above the title - // row. - gfx::Size scroller_size = scroll_content_->GetPreferredSize(); - scroller_->set_fixed_size( - gfx::Size(width() + scroller_->GetScrollBarLayoutWidth(), - scroller_size.height() - (size.height() - height()))); - } - views::View::Layout(); - - if (title_row_) { - // Always make sure the title row is bottom-aligned in non-MD. - gfx::Rect fbounds = title_row_->bounds(); - fbounds.set_y(height() - title_row_->height()); - title_row_->SetBoundsRect(fbounds); - } + if (scroller_ && !scroller_->is_bounded()) + scroller_->ClipHeightTo(0, scroller_->height()); } int TrayDetailsView::GetHeightForWidth(int width) const {
diff --git a/ash/common/system/tray/tray_details_view.h b/ash/common/system/tray/tray_details_view.h index 4668d46..b7021d6 100644 --- a/ash/common/system/tray/tray_details_view.h +++ b/ash/common/system/tray/tray_details_view.h
@@ -23,6 +23,7 @@ class BoxLayout; class CustomButton; class ProgressBar; +class ScrollView; } // namespace views namespace ash { @@ -30,7 +31,6 @@ class TrayDetailsViewTest; } // namespace test -class FixedSizedScrollView; class ScrollBorder; class SystemTrayItem; class TriView; @@ -52,7 +52,7 @@ SystemTrayItem* owner() { return owner_; } SpecialPopupRow* title_row() { return title_row_; } - FixedSizedScrollView* scroller() { return scroller_; } + views::ScrollView* scroller() { return scroller_; } views::View* scroll_content() { return scroll_content_; } protected: @@ -124,7 +124,7 @@ SystemTrayItem* owner_; views::BoxLayout* box_layout_; SpecialPopupRow* title_row_; // Not used in material design. - FixedSizedScrollView* scroller_; + views::ScrollView* scroller_; views::View* scroll_content_; views::ProgressBar* progress_bar_;
diff --git a/ash/common/system/tray/tray_popup_label_button.cc b/ash/common/system/tray/tray_popup_label_button.cc deleted file mode 100644 index 1289cd6..0000000 --- a/ash/common/system/tray/tray_popup_label_button.cc +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/common/system/tray/tray_popup_label_button.h" - -#include "ash/common/ash_constants.h" -#include "ash/common/material_design/material_design_controller.h" -#include "ash/common/system/tray/tray_popup_label_button_border.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/views/painter.h" - -namespace ash { - -TrayPopupLabelButton::TrayPopupLabelButton(views::ButtonListener* listener, - const base::string16& text) - : views::LabelButton(listener, text) { - DCHECK(!MaterialDesignController::IsSystemTrayMenuMaterial()); - SetBorder(std::unique_ptr<views::Border>(new TrayPopupLabelButtonBorder)); - SetFocusForPlatform(); - set_animate_on_state_change(false); - SetHorizontalAlignment(gfx::ALIGN_CENTER); - SetFocusPainter(views::Painter::CreateSolidFocusPainter( - kFocusBorderColor, gfx::Insets(1, 1, 2, 2))); -} - -TrayPopupLabelButton::~TrayPopupLabelButton() {} - -} // namespace ash
diff --git a/ash/common/system/tray/tray_popup_label_button.h b/ash/common/system/tray/tray_popup_label_button.h deleted file mode 100644 index ae78785..0000000 --- a/ash/common/system/tray/tray_popup_label_button.h +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_LABEL_BUTTON_H_ -#define ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_LABEL_BUTTON_H_ - -#include "base/macros.h" -#include "base/strings/string16.h" -#include "ui/views/controls/button/label_button.h" - -namespace ash { - -// A label button with custom alignment, border and focus border. -// TODO(estade): deprecated for MD. Use CreateTrayPopupButton instead. -// See crbug.com/614453 -class TrayPopupLabelButton : public views::LabelButton { - public: - TrayPopupLabelButton(views::ButtonListener* listener, - const base::string16& text); - ~TrayPopupLabelButton() override; - - private: - DISALLOW_COPY_AND_ASSIGN(TrayPopupLabelButton); -}; - -} // namespace ash - -#endif // ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_LABEL_BUTTON_H_
diff --git a/ash/common/system/tray/tray_popup_label_button_border.cc b/ash/common/system/tray/tray_popup_label_button_border.cc deleted file mode 100644 index 6813d0e..0000000 --- a/ash/common/system/tray/tray_popup_label_button_border.cc +++ /dev/null
@@ -1,93 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/common/system/tray/tray_popup_label_button_border.h" - -#include "base/i18n/rtl.h" -#include "grit/ash_resources.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/geometry/vector2d.h" -#include "ui/gfx/scoped_canvas.h" -#include "ui/native_theme/native_theme.h" -#include "ui/views/controls/button/label_button.h" -#include "ui/views/native_theme_delegate.h" - -namespace ash { - -TrayPopupLabelButtonBorder::TrayPopupLabelButtonBorder() - : LabelButtonAssetBorder(views::Button::STYLE_TEXTBUTTON) { - const int kTrayPopupLabelButtonBorderImagesNormal[] = { - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_BORDER, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_BORDER, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_BORDER, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND, - }; - SetPainter(false, views::Button::STATE_NORMAL, - views::Painter::CreateImageGridPainter( - kTrayPopupLabelButtonBorderImagesNormal)); - SetPainter(false, views::Button::STATE_DISABLED, - views::Painter::CreateImageGridPainter( - kTrayPopupLabelButtonBorderImagesNormal)); - - const int kTrayPopupLabelButtonBorderImagesHovered[] = { - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_BORDER, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_BORDER, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_BORDER, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_BORDER, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_HOVER_BACKGROUND, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_BORDER, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_BORDER, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_BORDER, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_BORDER, - }; - SetPainter(false, views::Button::STATE_HOVERED, - views::Painter::CreateImageGridPainter( - kTrayPopupLabelButtonBorderImagesHovered)); - SetPainter(false, views::Button::STATE_PRESSED, - views::Painter::CreateImageGridPainter( - kTrayPopupLabelButtonBorderImagesHovered)); - - const int kTrayPopupLabelButtonPaddingHorizontal = 16; - const int kTrayPopupLabelButtonPaddingVertical = 8; - set_insets(gfx::Insets(kTrayPopupLabelButtonPaddingVertical, - kTrayPopupLabelButtonPaddingHorizontal, - kTrayPopupLabelButtonPaddingVertical, - kTrayPopupLabelButtonPaddingHorizontal)); -} - -TrayPopupLabelButtonBorder::~TrayPopupLabelButtonBorder() {} - -void TrayPopupLabelButtonBorder::Paint(const views::View& view, - gfx::Canvas* canvas) { - const views::NativeThemeDelegate* native_theme_delegate = - static_cast<const views::LabelButton*>(&view); - ui::NativeTheme::ExtraParams extra; - const ui::NativeTheme::State state = - native_theme_delegate->GetThemeState(&extra); - if (state == ui::NativeTheme::kNormal || - state == ui::NativeTheme::kDisabled) { - // In normal and disabled state, the border is a vertical bar separating the - // button from the preceding sibling. If this button is its parent's first - // visible child, the separator bar should be omitted. - const views::View* first_visible_child = NULL; - for (int i = 0; i < view.parent()->child_count(); ++i) { - const views::View* child = view.parent()->child_at(i); - if (child->visible()) { - first_visible_child = child; - break; - } - } - if (first_visible_child == &view) - return; - } - gfx::ScopedRTLFlipCanvas scoped_canvas(canvas, view.width()); - LabelButtonAssetBorder::Paint(view, canvas); -} - -} // namespace ash
diff --git a/ash/common/system/tray/tray_popup_label_button_border.h b/ash/common/system/tray/tray_popup_label_button_border.h deleted file mode 100644 index 670d6cf..0000000 --- a/ash/common/system/tray/tray_popup_label_button_border.h +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_LABEL_BUTTON_BORDER_H_ -#define ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_LABEL_BUTTON_BORDER_H_ - -#include "base/macros.h" -#include "ui/views/controls/button/label_button_border.h" - -namespace ash { - -// A border for label buttons that paints a vertical separator in normal state -// and a custom hover effect in hovered or pressed state. -class TrayPopupLabelButtonBorder : public views::LabelButtonAssetBorder { - public: - TrayPopupLabelButtonBorder(); - ~TrayPopupLabelButtonBorder() override; - - // views::LabelButtonAssetBorder: - void Paint(const views::View& view, gfx::Canvas* canvas) override; - - private: - DISALLOW_COPY_AND_ASSIGN(TrayPopupLabelButtonBorder); -}; - -} // namespace ash - -#endif // ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_LABEL_BUTTON_BORDER_H_
diff --git a/ash/common/system/tray/tray_popup_utils.cc b/ash/common/system/tray/tray_popup_utils.cc index 3c2a607f..cc04e18 100644 --- a/ash/common/system/tray/tray_popup_utils.cc +++ b/ash/common/system/tray/tray_popup_utils.cc
@@ -15,8 +15,6 @@ #include "ash/common/system/tray/size_range_layout.h" #include "ash/common/system/tray/tray_constants.h" #include "ash/common/system/tray/tray_popup_item_style.h" -#include "ash/common/system/tray/tray_popup_label_button.h" -#include "ash/common/system/tray/tray_popup_label_button_border.h" #include "ash/common/wm_shell.h" #include "base/memory/ptr_util.h" #include "ui/base/l10n/l10n_util.h" @@ -112,37 +110,24 @@ BorderlessLabelButton(views::ButtonListener* listener, const base::string16& text) : LabelButton(listener, text) { - if (MaterialDesignController::IsSystemTrayMenuMaterial()) { - SetInkDropMode(views::InkDropHostView::InkDropMode::ON); - set_has_ink_drop_action_on_click(true); - set_ink_drop_base_color(kTrayPopupInkDropBaseColor); - set_ink_drop_visible_opacity(kTrayPopupInkDropRippleOpacity); - const int kHorizontalPadding = 20; - SetBorder(views::CreateEmptyBorder(gfx::Insets(0, kHorizontalPadding))); - TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::BUTTON); - style.SetupLabel(label()); - SetFocusPainter(TrayPopupUtils::CreateFocusPainter()); - } else { - SetBorder(std::unique_ptr<views::Border>(new TrayPopupLabelButtonBorder)); - SetFocusPainter(views::Painter::CreateSolidFocusPainter( - kFocusBorderColor, gfx::Insets(1, 1, 2, 2))); - set_animate_on_state_change(false); - } + const int kHorizontalPadding = 20; + SetBorder(views::CreateEmptyBorder(gfx::Insets(0, kHorizontalPadding))); + TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::BUTTON); + style.SetupLabel(label()); SetHorizontalAlignment(gfx::ALIGN_CENTER); - SetFocusForPlatform(); + SetFocusPainter(TrayPopupUtils::CreateFocusPainter()); + + TrayPopupUtils::ConfigureTrayPopupButton(this); } ~BorderlessLabelButton() override {} // views::LabelButton: - int GetHeightForWidth(int width) const override { - if (MaterialDesignController::IsSystemTrayMenuMaterial()) - return kMenuButtonSize; - - return LabelButton::GetHeightForWidth(width); - } + int GetHeightForWidth(int width) const override { return kMenuButtonSize; } private: + // TODO(estade,bruthig): there's a lot in common here with ActionableView. + // Find a way to share. See related TODO on InkDropHostView::SetInkDropMode(). std::unique_ptr<views::InkDrop> CreateInkDrop() override { return TrayPopupUtils::CreateInkDrop(TrayPopupInkDropStyle::INSET_BOUNDS, this); @@ -280,6 +265,19 @@ kFocusBorderColor, kFocusBorderThickness, gfx::InsetsF()); } +void TrayPopupUtils::ConfigureTrayPopupButton(views::CustomButton* button) { + // All buttons that call into here want this focus painter, but + // SetFocusPainter is defined separately on derived classes and isn't part of + // CustomButton. TODO(estade): Address this. + // button->SetFocusPainter(TrayPopupUtils::CreateFocusPainter()); + button->SetFocusForPlatform(); + + button->SetInkDropMode(views::InkDropHostView::InkDropMode::ON); + button->set_has_ink_drop_action_on_click(true); + button->set_ink_drop_base_color(kTrayPopupInkDropBaseColor); + button->set_ink_drop_visible_opacity(kTrayPopupInkDropRippleOpacity); +} + void TrayPopupUtils::ConfigureAsStickyHeader(views::View* view) { view->set_id(VIEW_ID_STICKY_HEADER); view->set_background( @@ -320,9 +318,6 @@ views::LabelButton* TrayPopupUtils::CreateTrayPopupButton( views::ButtonListener* listener, const base::string16& text) { - if (!MaterialDesignController::IsSystemTrayMenuMaterial()) - return CreateTrayPopupBorderlessButton(listener, text); - auto* button = views::MdTextButton::Create(listener, text); button->SetProminent(true); return button;
diff --git a/ash/common/system/tray/tray_popup_utils.h b/ash/common/system/tray/tray_popup_utils.h index 1e73c1fc..ecec2227 100644 --- a/ash/common/system/tray/tray_popup_utils.h +++ b/ash/common/system/tray/tray_popup_utils.h
@@ -15,6 +15,7 @@ namespace views { class ButtonListener; +class CustomButton; class ImageView; class InkDrop; class InkDropRipple; @@ -113,6 +114,9 @@ // Creates a default focus painter used for most things in tray popups. static std::unique_ptr<views::Painter> CreateFocusPainter(); + // Common setup for various buttons in the system menu. + static void ConfigureTrayPopupButton(views::CustomButton* button); + // Sets up |view| to be a sticky header in a tray detail scroll view. static void ConfigureAsStickyHeader(views::View* view);
diff --git a/ash/common/system/tray_accessibility.cc b/ash/common/system/tray_accessibility.cc index 5ec4704..9e1fda5 100644 --- a/ash/common/system/tray_accessibility.cc +++ b/ash/common/system/tray_accessibility.cc
@@ -17,7 +17,6 @@ #include "ash/common/system/tray/tray_details_view.h" #include "ash/common/system/tray/tray_item_more.h" #include "ash/common/system/tray/tray_popup_item_style.h" -#include "ash/common/system/tray/tray_popup_label_button.h" #include "ash/common/system/tray/tray_popup_utils.h" #include "ash/common/system/tray/tri_view.h" #include "ash/common/wm_shell.h" @@ -236,33 +235,6 @@ void AccessibilityDetailedView::AppendHelpEntries() { DCHECK(!UseMdMenu()); - // Currently the help page requires a browser window. - // TODO(yoshiki): show this even on login/lock screen. crbug.com/158286 - if (!TrayPopupUtils::CanOpenWebUISettings(login_)) - return; - - views::View* bottom_row = new View(); - views::BoxLayout* layout = new views::BoxLayout( - views::BoxLayout::kHorizontal, kTrayMenuBottomRowPadding, - kTrayMenuBottomRowPadding, kTrayMenuBottomRowPaddingBetweenItems); - layout->SetDefaultFlex(1); - bottom_row->SetLayoutManager(layout); - - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - - TrayPopupLabelButton* help = new TrayPopupLabelButton( - this, - bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_LEARN_MORE)); - bottom_row->AddChildView(help); - help_view_ = help; - - TrayPopupLabelButton* settings = new TrayPopupLabelButton( - this, - bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SETTINGS)); - bottom_row->AddChildView(settings); - settings_view_ = settings; - - AddChildView(bottom_row); } HoverHighlightView* AccessibilityDetailedView::AddScrollListItem(
diff --git a/ash/common/system/user/rounded_image_view.cc b/ash/common/system/user/rounded_image_view.cc index d90df62..d7717b8 100644 --- a/ash/common/system/user/rounded_image_view.cc +++ b/ash/common/system/user/rounded_image_view.cc
@@ -63,14 +63,14 @@ SkIntToScalar(corner_radius_[3]), SkIntToScalar(corner_radius_[3])}; SkPath path; path.addRoundRect(gfx::RectToSkRect(image_bounds), kRadius); - cc::PaintFlags paint; - paint.setAntiAlias(true); + cc::PaintFlags flags; + flags.setAntiAlias(true); const bool grayscale = !active_user_ && !MaterialDesignController::IsSystemTrayMenuMaterial(); - paint.setBlendMode(grayscale ? SkBlendMode::kLuminosity + flags.setBlendMode(grayscale ? SkBlendMode::kLuminosity : SkBlendMode::kSrcOver); canvas->DrawImageInPath(resized_, image_bounds.x(), image_bounds.y(), path, - paint); + flags); } } // namespace tray
diff --git a/ash/common/system/user/tray_user_unittest.cc b/ash/common/system/user/tray_user_unittest.cc index ce12f3f..faa7493 100644 --- a/ash/common/system/user/tray_user_unittest.cc +++ b/ash/common/system/user/tray_user_unittest.cc
@@ -4,12 +4,10 @@ #include <vector> -#include "ash/common/material_design/material_design_controller.h" #include "ash/common/shell_delegate.h" #include "ash/common/system/tray/system_tray.h" #include "ash/common/system/tray/tray_constants.h" #include "ash/common/system/user/tray_user.h" -#include "ash/common/system/user/tray_user_separator.h" #include "ash/common/system/user/user_view.h" #include "ash/common/test/test_session_state_delegate.h" #include "ash/common/wm_shell.h" @@ -30,10 +28,6 @@ namespace { -bool UseMd() { - return MaterialDesignController::IsSystemTrayMenuMaterial(); -} - class TrayUserTest : public test::AshTestBase { public: TrayUserTest() = default; @@ -57,7 +51,6 @@ SystemTray* tray() { return tray_; } test::TestSessionStateDelegate* delegate() { return delegate_; } TrayUser* tray_user(int index) { return tray_user_[index]; } - TrayUserSeparator* tray_user_separator() { return tray_user_separator_; } private: SystemTray* tray_ = nullptr; @@ -66,10 +59,6 @@ // Note that the ownership of these items is on the shelf. std::vector<TrayUser*> tray_user_; - // The separator between the tray users and the rest of the menu. - // Note: The item will get owned by the shelf. Not used in Material Design. - TrayUserSeparator* tray_user_separator_ = nullptr; - DISALLOW_COPY_AND_ASSIGN(TrayUserTest); }; @@ -94,11 +83,6 @@ tray_user_.push_back(new TrayUser(tray_, i)); tray_->AddTrayItem(base::WrapUnique(tray_user_[i])); } - if (!UseMd()) { - // We then add also the separator. - tray_user_separator_ = new TrayUserSeparator(tray_); - tray_->AddTrayItem(base::WrapUnique(tray_user_separator_)); - } } void TrayUserTest::ShowTrayMenu(ui::test::EventGenerator* generator) { @@ -136,8 +120,7 @@ EXPECT_EQ(kTrayItemSize, size.height()); } -// Make sure that in single user mode the user panel cannot be activated and no -// separators are being created. +// Make sure that in single user mode the user panel cannot be activated. TEST_F(TrayUserTest, SingleUserModeDoesNotAllowAddingUser) { InitializeParameters(1, false); @@ -148,8 +131,6 @@ for (int i = 0; i < delegate()->GetMaximumNumberOfLoggedInUsers(); i++) EXPECT_EQ(TrayUser::HIDDEN, tray_user(i)->GetStateForTest()); - if (!UseMd()) - EXPECT_FALSE(tray_user_separator()->separator_shown()); ShowTrayMenu(&generator); @@ -159,8 +140,6 @@ for (int i = 0; i < delegate()->GetMaximumNumberOfLoggedInUsers(); i++) EXPECT_EQ(i == 0 ? TrayUser::SHOWN : TrayUser::HIDDEN, tray_user(i)->GetStateForTest()); - if (!UseMd()) - EXPECT_FALSE(tray_user_separator()->separator_shown()); tray()->CloseSystemBubble(); } @@ -195,7 +174,7 @@ } // Make sure that in multi user mode the user panel can be activated and there -// will be one panel for each user plus one additional separator at the end. +// will be one panel for each user. // Note: the mouse watcher (for automatic closing upon leave) cannot be tested // here since it does not work with the event system in unit tests. TEST_F(TrayUserTest, MultiUserModeDoesNotAllowToAddUser) { @@ -215,11 +194,8 @@ EXPECT_FALSE(tray()->IsAnyBubbleVisible()); for (int i = 0; i < max_users; i++) EXPECT_FALSE(tray_user(i)->GetStateForTest()); - if (!UseMd()) - EXPECT_FALSE(tray_user_separator()->separator_shown()); // After clicking on the tray the menu should get shown and for each logged - // in user we should get a visible item. In addition, the separator should - // show up when we reach more than one user. + // in user we should get a visible item. ShowTrayMenu(&generator); EXPECT_TRUE(tray()->HasSystemBubble()); @@ -229,10 +205,6 @@ tray_user(i)->GetStateForTest()); } - // Check the visibility of the separator. - if (!UseMd()) - EXPECT_EQ(j > 1 ? true : false, tray_user_separator()->separator_shown()); - // Move the mouse over the user item and it should hover. MoveOverUserItem(&generator, 0); EXPECT_EQ(TrayUser::HOVERED, tray_user(0)->GetStateForTest());
diff --git a/ash/common/system/user/user_view.cc b/ash/common/system/user/user_view.cc index b94f1868..0810d2ce 100644 --- a/ash/common/system/user/user_view.cc +++ b/ash/common/system/user/user_view.cc
@@ -17,8 +17,6 @@ #include "ash/common/system/tray/system_tray_delegate.h" #include "ash/common/system/tray/tray_constants.h" #include "ash/common/system/tray/tray_popup_item_style.h" -#include "ash/common/system/tray/tray_popup_label_button.h" -#include "ash/common/system/tray/tray_popup_label_button_border.h" #include "ash/common/system/tray/tray_popup_utils.h" #include "ash/common/system/user/button_from_view.h" #include "ash/common/system/user/login_status.h" @@ -56,30 +54,6 @@ return MaterialDesignController::IsSystemTrayMenuMaterial(); } -const int kPublicAccountLogoutButtonBorderImagesNormal[] = { - IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND, - IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND, - IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND, -}; - -const int kPublicAccountLogoutButtonBorderImagesHovered[] = { - IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, - IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, - IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, - IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, - IDR_AURA_TRAY_POPUP_LABEL_BUTTON_HOVER_BACKGROUND, - IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, - IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, - IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, - IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER, -}; - // When a hover border is used, it is starting this many pixels before the icon // position. const int kTrayUserTileHoverBorderInset = 10; @@ -490,29 +464,9 @@ } void UserView::AddLogoutButton(LoginStatus login) { - const base::string16 title = - user::GetLocalizedSignOutStringForStatus(login, true); - auto* logout_button = - TrayPopupUtils::CreateTrayPopupBorderlessButton(this, title); - logout_button->SetAccessibleName(title); - logout_button_ = logout_button; - if (UseMd()) { - AddChildView(TrayPopupUtils::CreateVerticalSeparator()); - } else if (login == LoginStatus::PUBLIC) { - // In public account mode, the logout button border has a custom color. - std::unique_ptr<TrayPopupLabelButtonBorder> border( - new TrayPopupLabelButtonBorder()); - border->SetPainter(false, views::Button::STATE_NORMAL, - views::Painter::CreateImageGridPainter( - kPublicAccountLogoutButtonBorderImagesNormal)); - border->SetPainter(false, views::Button::STATE_HOVERED, - views::Painter::CreateImageGridPainter( - kPublicAccountLogoutButtonBorderImagesHovered)); - border->SetPainter(false, views::Button::STATE_PRESSED, - views::Painter::CreateImageGridPainter( - kPublicAccountLogoutButtonBorderImagesHovered)); - logout_button_->SetBorder(std::move(border)); - } + AddChildView(TrayPopupUtils::CreateVerticalSeparator()); + logout_button_ = TrayPopupUtils::CreateTrayPopupBorderlessButton( + this, user::GetLocalizedSignOutStringForStatus(login, true)); AddChildView(logout_button_); }
diff --git a/ash/common/system/web_notification/web_notification_tray.cc b/ash/common/system/web_notification/web_notification_tray.cc index ce82103..7999f51 100644 --- a/ash/common/system/web_notification/web_notification_tray.cc +++ b/ash/common/system/web_notification/web_notification_tray.cc
@@ -357,18 +357,13 @@ new message_center::MessageCenterBubble(message_center(), message_center_tray_.get()); - int max_height; - if (IsHorizontalAlignment(shelf_alignment())) { - max_height = shelf()->GetIdealBounds().y(); - } else { - // Assume the status area and bubble bottoms are aligned when vertical. - gfx::Rect bounds_in_root = - status_area_window_->GetRootWindow()->ConvertRectFromScreen( - status_area_window_->GetBoundsInScreen()); - max_height = bounds_in_root.bottom(); - } - message_center_bubble->SetMaxHeight( - std::max(0, max_height - GetTrayConstant(TRAY_SPACING))); + // In the horizontal case, message center starts from the top of the shelf. + // In the vertical case, it starts from the bottom of WebNotificationTray. + const int max_height = IsHorizontalAlignment(shelf_alignment()) + ? shelf()->GetIdealBounds().y() + : GetBoundsInScreen().bottom(); + message_center_bubble->SetMaxHeight(max_height); + if (show_settings) message_center_bubble->SetSettingsVisible();
diff --git a/ash/common/test/test_palette_delegate.cc b/ash/common/test/test_palette_delegate.cc index d05ec4a..ab5692f 100644 --- a/ash/common/test/test_palette_delegate.cc +++ b/ash/common/test/test_palette_delegate.cc
@@ -25,10 +25,6 @@ return has_note_app_; } -void TestPaletteDelegate::SetStylusStateChangedCallback( - const PaletteDelegate::OnStylusStateChangedCallback& - on_stylus_state_changed) {} - bool TestPaletteDelegate::ShouldAutoOpenPalette() { return should_auto_open_palette_; }
diff --git a/ash/common/test/test_palette_delegate.h b/ash/common/test/test_palette_delegate.h index 837c0e042..f0fc5e55 100644 --- a/ash/common/test/test_palette_delegate.h +++ b/ash/common/test/test_palette_delegate.h
@@ -46,8 +46,6 @@ const EnableListener& on_state_changed) override; void CreateNote() override; bool HasNoteApp() override; - void SetStylusStateChangedCallback( - const OnStylusStateChangedCallback& on_stylus_state_changed) override; bool ShouldAutoOpenPalette() override; bool ShouldShowPalette() override; void TakeScreenshot() override;
diff --git a/ash/common/test/test_shelf_item_delegate.cc b/ash/common/test/test_shelf_item_delegate.cc index e086259..e257d6e 100644 --- a/ash/common/test/test_shelf_item_delegate.cc +++ b/ash/common/test/test_shelf_item_delegate.cc
@@ -26,9 +26,9 @@ return kNoAction; } -ui::SimpleMenuModel* TestShelfItemDelegate::CreateApplicationMenu( - int event_flags) { - return nullptr; +ShelfAppMenuItemList TestShelfItemDelegate::GetAppMenuItems(int event_flags) { + // Return an empty item list to avoid showing an application menu. + return ShelfAppMenuItemList(); } void TestShelfItemDelegate::Close() {}
diff --git a/ash/common/test/test_shelf_item_delegate.h b/ash/common/test/test_shelf_item_delegate.h index 62743ac..a2f7893 100644 --- a/ash/common/test/test_shelf_item_delegate.h +++ b/ash/common/test/test_shelf_item_delegate.h
@@ -6,7 +6,6 @@ #define ASH_COMMON_TEST_TEST_SHELF_ITEM_DELEGATE_H_ #include "ash/common/shelf/shelf_item_delegate.h" -#include "base/compiler_specific.h" #include "base/macros.h" namespace ash { @@ -24,7 +23,7 @@ // ShelfItemDelegate: ShelfItemDelegate::PerformedAction ItemSelected( const ui::Event& event) override; - ui::SimpleMenuModel* CreateApplicationMenu(int event_flags) override; + ShelfAppMenuItemList GetAppMenuItems(int event_flags) override; void Close() override; private:
diff --git a/ash/common/wm/dock/docked_window_layout_manager.cc b/ash/common/wm/dock/docked_window_layout_manager.cc index 99b3613..a71dbe8 100644 --- a/ash/common/wm/dock/docked_window_layout_manager.cc +++ b/ash/common/wm/dock/docked_window_layout_manager.cc
@@ -94,8 +94,8 @@ const gfx::ImageSkia& shelf_background(alignment_ == DOCKED_ALIGNMENT_LEFT ? shelf_background_left_ : shelf_background_right_); - cc::PaintFlags paint; - paint.setAlpha(asset_background_alpha_); + cc::PaintFlags flags; + flags.setAlpha(asset_background_alpha_); recorder.canvas()->DrawImageInt( shelf_background, 0, 0, shelf_background.width(), shelf_background.height(), @@ -103,7 +103,7 @@ ? local_window_bounds.width() - shelf_background.width() : 0, 0, shelf_background.width(), local_window_bounds.height(), false, - paint); + flags); recorder.canvas()->DrawImageInt( shelf_background, alignment_ == DOCKED_ALIGNMENT_LEFT ? 0 @@ -111,7 +111,7 @@ 0, 1, shelf_background.height(), alignment_ == DOCKED_ALIGNMENT_LEFT ? 0 : shelf_background.width(), 0, local_window_bounds.width() - shelf_background.width(), - local_window_bounds.height(), false, paint); + local_window_bounds.height(), false, flags); } }
diff --git a/ash/common/wm/overview/window_grid.cc b/ash/common/wm/overview/window_grid.cc index 5757417..7cea80b 100644 --- a/ash/common/wm/overview/window_grid.cc +++ b/ash/common/wm/overview/window_grid.cc
@@ -119,8 +119,6 @@ bounds.set_height(bounds.height() + radius); path.addRoundRect(gfx::RectToSkRect(bounds), kRadius); - cc::PaintFlags paint; - paint.setAntiAlias(true); canvas->ClipPath(path, true); canvas->DrawColor(background_); } @@ -183,23 +181,23 @@ path.addRoundRect(gfx::RectFToSkRect(border_rect_f), scaled_corner_radius, scaled_corner_radius); - SkPaint paint; - paint.setStyle(SkPaint::kStroke_Style); - paint.setStrokeWidth(1); - paint.setAntiAlias(true); + SkPaint flags; + flags.setStyle(SkPaint::kStroke_Style); + flags.setStrokeWidth(1); + flags.setAntiAlias(true); SkPath stroke_path; - paint.getFillPath(path, &stroke_path); + flags.getFillPath(path, &stroke_path); SkPath fill_path; Op(path, stroke_path, kDifference_SkPathOp, &fill_path); - paint.setStyle(SkPaint::kFill_Style); - paint.setColor(get_color()); - canvas->sk_canvas()->drawPath(fill_path, paint); + flags.setStyle(SkPaint::kFill_Style); + flags.setColor(get_color()); + canvas->sk_canvas()->drawPath(fill_path, flags); if (border_thickness_ > 0) { - paint.setColor(border_color_); - canvas->sk_canvas()->drawPath(stroke_path, paint); + flags.setColor(border_color_); + canvas->sk_canvas()->drawPath(stroke_path, flags); } }
diff --git a/ash/common/wm/overview/window_selector.cc b/ash/common/wm/overview/window_selector.cc index 322f7ef..7233f45e 100644 --- a/ash/common/wm/overview/window_selector.cc +++ b/ash/common/wm/overview/window_selector.cc
@@ -116,8 +116,6 @@ gfx::Rect bounds(size()); path.addRoundRect(gfx::RectToSkRect(bounds), kRadius); - cc::PaintFlags paint; - paint.setAntiAlias(true); canvas->ClipPath(path, true); canvas->DrawColor(background_); }
diff --git a/ash/common/wm/overview/window_selector_item.cc b/ash/common/wm/overview/window_selector_item.cc index 0b1cfa0..09bc825 100644 --- a/ash/common/wm/overview/window_selector_item.cc +++ b/ash/common/wm/overview/window_selector_item.cc
@@ -267,8 +267,8 @@ gfx::Rect bounds(size()); path.addRoundRect(gfx::RectToSkRect(bounds), kRadius); - cc::PaintFlags paint; - paint.setAntiAlias(true); + cc::PaintFlags flags; + flags.setAntiAlias(true); canvas->ClipPath(path, true); SkColor target_color = initial_color_;
diff --git a/ash/common/wm/panels/panel_layout_manager.cc b/ash/common/wm/panels/panel_layout_manager.cc index 07f1a7a9..6acd55a 100644 --- a/ash/common/wm/panels/panel_layout_manager.cc +++ b/ash/common/wm/panels/panel_layout_manager.cc
@@ -77,10 +77,10 @@ break; } // Hard code the arrow color for now. - cc::PaintFlags paint; - paint.setStyle(cc::PaintFlags::kFill_Style); - paint.setColor(SkColorSetARGB(0xff, 0xe5, 0xe5, 0xe5)); - canvas->DrawPath(path, paint); + cc::PaintFlags flags; + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setColor(SkColorSetARGB(0xff, 0xe5, 0xe5, 0xe5)); + canvas->DrawPath(path, flags); } ShelfAlignment alignment() { return alignment_; }
diff --git a/ash/common/wm/window_cycle_list.cc b/ash/common/wm/window_cycle_list.cc index 4180768..fd63499 100644 --- a/ash/common/wm/window_cycle_list.cc +++ b/ash/common/wm/window_cycle_list.cc
@@ -353,15 +353,15 @@ // We can't set a bg on the mirror container itself because the highlight // view needs to be on top of the bg but behind the target windows. const gfx::RectF shield_bounds(mirror_container_->bounds()); - cc::PaintFlags paint; - paint.setColor(SkColorSetA(SK_ColorBLACK, 0xE6)); - paint.setStyle(cc::PaintFlags::kFill_Style); + cc::PaintFlags flags; + flags.setColor(SkColorSetA(SK_ColorBLACK, 0xE6)); + flags.setStyle(cc::PaintFlags::kFill_Style); float corner_radius = 0.f; if (shield_bounds.width() < width()) { - paint.setAntiAlias(true); + flags.setAntiAlias(true); corner_radius = kBackgroundCornerRadius; } - canvas->DrawRoundRect(shield_bounds, corner_radius, paint); + canvas->DrawRoundRect(shield_bounds, corner_radius, flags); } View* GetInitiallyFocusedView() override {
diff --git a/ash/laser/laser_pointer_controller.cc b/ash/laser/laser_pointer_controller.cc index 3559bad4..e979549 100644 --- a/ash/laser/laser_pointer_controller.cc +++ b/ash/laser/laser_pointer_controller.cc
@@ -70,7 +70,7 @@ // Start a new laser session if the stylus is pressed but not pressed over the // palette. if (event->type() == ui::ET_TOUCH_PRESSED && - !PaletteContainsPointInScreen(event_location)) { + !palette_utils::PaletteContainsPointInScreen(event_location)) { DestroyLaserPointerView(); UpdateLaserPointerView(current_window, event_location, event); }
diff --git a/ash/laser/laser_pointer_view.cc b/ash/laser/laser_pointer_view.cc index 1a209a07..5374ce95 100644 --- a/ash/laser/laser_pointer_view.cc +++ b/ash/laser/laser_pointer_view.cc
@@ -218,9 +218,9 @@ if (laser_points_.IsEmpty()) return; - cc::PaintFlags paint; - paint.setStyle(cc::PaintFlags::kFill_Style); - paint.setAntiAlias(true); + cc::PaintFlags flags; + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setAntiAlias(true); // Compute the offset of the current widget. gfx::Vector2d widget_offset( @@ -262,16 +262,16 @@ i == num_points - 1); SkPath path = current_segment.path(); - paint.setColor(SkColorSetA(kPointColor, current_opacity)); - canvas->DrawPath(path, paint); + flags.setColor(SkColorSetA(kPointColor, current_opacity)); + canvas->DrawPath(path, flags); previous_segment_points = current_segment.path_points(); previous_radius = current_radius; previous_point = current_point; } // Draw the last point as a circle. - paint.setColor(SkColorSetA(kPointColor, current_opacity)); - paint.setStyle(cc::PaintFlags::kFill_Style); - canvas->DrawCircle(current_point.location, kPointInitialRadius, paint); + flags.setColor(SkColorSetA(kPointColor, current_opacity)); + flags.setStyle(cc::PaintFlags::kFill_Style); + canvas->DrawCircle(current_point.location, kPointInitialRadius, flags); } } // namespace ash
diff --git a/ash/magnifier/partial_magnification_controller.cc b/ash/magnifier/partial_magnification_controller.cc index b4fc5c0..3cbedb8 100644 --- a/ash/magnifier/partial_magnification_controller.cc +++ b/ash/magnifier/partial_magnification_controller.cc
@@ -105,14 +105,14 @@ void OnPaintLayer(const ui::PaintContext& context) override { ui::PaintRecorder recorder(context, layer()->size()); - cc::PaintFlags paint; - paint.setAlpha(255); - paint.setAntiAlias(true); + cc::PaintFlags flags; + flags.setAlpha(255); + flags.setAntiAlias(true); // Stroke is used for clipping the border which consists of the rendered // border |kBorderSize| and the magnifier shadow |kShadowThickness| and // |kShadowOffset|. - paint.setStrokeWidth(kBorderSize + kShadowThickness + kShadowOffset); - paint.setStyle(is_border_ ? cc::PaintFlags::kStroke_Style + flags.setStrokeWidth(kBorderSize + kShadowThickness + kShadowOffset); + flags.setStyle(is_border_ ? cc::PaintFlags::kStroke_Style : cc::PaintFlags::kFill_Style); // If we want to clip the magnifier zone use the magnifiers radius. @@ -123,7 +123,7 @@ int clipping_radius = kMagnifierRadius; if (is_border_) clipping_radius += (kShadowThickness + kShadowOffset + kBorderSize) / 2; - recorder.canvas()->DrawCircle(rect.CenterPoint(), clipping_radius, paint); + recorder.canvas()->DrawCircle(rect.CenterPoint(), clipping_radius, flags); } void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {} @@ -159,41 +159,41 @@ ui::PaintRecorder recorder(context, magnifier_window_bounds_.size()); // Draw the shadow. - cc::PaintFlags shadow_paint; - shadow_paint.setAntiAlias(true); - shadow_paint.setColor(SK_ColorTRANSPARENT); - shadow_paint.setLooper( + cc::PaintFlags shadow_flags; + shadow_flags.setAntiAlias(true); + shadow_flags.setColor(SK_ColorTRANSPARENT); + shadow_flags.setLooper( gfx::CreateShadowDrawLooperCorrectBlur(magnifier_shadows_)); gfx::Rect shadow_bounds(magnifier_window_bounds_.size()); recorder.canvas()->DrawCircle( shadow_bounds.CenterPoint(), shadow_bounds.width() / 2 - kShadowThickness - kShadowOffset, - shadow_paint); + shadow_flags); - cc::PaintFlags border_paint; - border_paint.setAntiAlias(true); - border_paint.setStyle(cc::PaintFlags::kStroke_Style); + cc::PaintFlags border_flags; + border_flags.setAntiAlias(true); + border_flags.setStyle(cc::PaintFlags::kStroke_Style); // The radius of the magnifier and its border. const int magnifier_radius = kMagnifierRadius + kBorderSize; // Draw the inner border. - border_paint.setStrokeWidth(kBorderSize); - border_paint.setColor(kBorderColor); + border_flags.setStrokeWidth(kBorderSize); + border_flags.setColor(kBorderColor); recorder.canvas()->DrawCircle(magnifier_window_bounds_.CenterPoint(), magnifier_radius - kBorderSize / 2, - border_paint); + border_flags); // Draw border outer outline and then draw the border inner outline. - border_paint.setStrokeWidth(kBorderOutlineThickness); - border_paint.setColor(kBorderOutlineColor); + border_flags.setStrokeWidth(kBorderOutlineThickness); + border_flags.setColor(kBorderOutlineColor); recorder.canvas()->DrawCircle( magnifier_window_bounds_.CenterPoint(), - magnifier_radius - kBorderOutlineThickness / 2, border_paint); + magnifier_radius - kBorderOutlineThickness / 2, border_flags); recorder.canvas()->DrawCircle( magnifier_window_bounds_.CenterPoint(), magnifier_radius - kBorderSize + kBorderOutlineThickness / 2, - border_paint); + border_flags); } void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {} @@ -283,7 +283,7 @@ // If the stylus is pressed on the palette icon or widget, do not activate. if (event->type() == ui::ET_TOUCH_PRESSED && - !PaletteContainsPointInScreen(screen_point)) { + !palette_utils::PaletteContainsPointInScreen(screen_point)) { SetActive(true); } @@ -311,7 +311,7 @@ host_widget_->SetBounds(GetBounds(point)); // If the stylus is over the palette icon or widget, do not consume the event. - if (!PaletteContainsPointInScreen(screen_point)) + if (!palette_utils::PaletteContainsPointInScreen(screen_point)) event->StopPropagation(); }
diff --git a/ash/mus/BUILD.gn b/ash/mus/BUILD.gn index fa7d5ed..60220c0 100644 --- a/ash/mus/BUILD.gn +++ b/ash/mus/BUILD.gn
@@ -38,7 +38,6 @@ "frame/custom_frame_view_mus.h", "frame/detached_title_area_renderer.cc", "frame/detached_title_area_renderer.h", - "frame/detached_title_area_renderer_host.h", "keyboard_ui_mus.cc", "keyboard_ui_mus.h", "move_event_handler.cc",
diff --git a/ash/mus/frame/detached_title_area_renderer.cc b/ash/mus/frame/detached_title_area_renderer.cc index f8fc51d..c6f42235 100644 --- a/ash/mus/frame/detached_title_area_renderer.cc +++ b/ash/mus/frame/detached_title_area_renderer.cc
@@ -5,36 +5,61 @@ #include "ash/mus/frame/detached_title_area_renderer.h" #include "ash/common/frame/header_view.h" -#include "ash/mus/frame/detached_title_area_renderer_host.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm_window.h" +#include "ash/mus/property_util.h" +#include "ash/mus/window_manager.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/aura/client/transient_window_client.h" +#include "ui/aura/mus/property_converter.h" +#include "ui/aura/mus/property_utils.h" #include "ui/aura/window.h" +#include "ui/base/class_property.h" #include "ui/views/view.h" #include "ui/views/widget/native_widget_aura.h" #include "ui/views/widget/widget.h" +DECLARE_UI_CLASS_PROPERTY_TYPE(ash::mus::DetachedTitleAreaRendererForClient*); + namespace ash { namespace mus { +namespace { -DetachedTitleAreaRenderer::DetachedTitleAreaRenderer( - DetachedTitleAreaRendererHost* host, - views::Widget* frame, - const gfx::Rect& bounds, - Source source) - : host_(host), frame_(frame), widget_(new views::Widget) { - views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); - params.delegate = this; - params.name = "DetachedTitleAreaRenderer"; - params.activatable = views::Widget::InitParams::ACTIVATABLE_NO; - views::NativeWidgetAura* native_widget = - new views::NativeWidgetAura(widget_, true); - params.native_widget = native_widget; - // TODO: making the reveal window a sibling is likely problematic. - // http://crbug.com/640392, see also comment in GetVisibleBoundsInScreen(). - params.parent = frame->GetNativeView()->parent(); - params.bounds = bounds; - widget_->Init(params); - params.parent->StackChildAbove(widget_->GetNativeView(), - frame->GetNativeView()); - HeaderView* header_view = new HeaderView(frame_); +DEFINE_UI_CLASS_PROPERTY_KEY(DetachedTitleAreaRendererForClient*, + kDetachedTitleAreaRendererKey, + nullptr); + +// Used to indicate why this is being created. See header for description of +// types. +enum class Source { + CLIENT, + INTERNAL, +}; + +// Configures the common InitParams. +std::unique_ptr<views::Widget::InitParams> CreateInitParams( + const char* debug_name) { + std::unique_ptr<views::Widget::InitParams> params = + base::MakeUnique<views::Widget::InitParams>( + views::Widget::InitParams::TYPE_POPUP); + params->name = debug_name; + params->activatable = views::Widget::InitParams::ACTIVATABLE_NO; + return params; +} + +// Configures properties common to both types. +void ConfigureCommonWidgetProperties(views::Widget* widget) { + aura::Window* window = widget->GetNativeView(); + // Default animations conflict with the reveal animation, so turn off the + // default animation. + window->SetProperty(aura::client::kAnimationsDisabledKey, true); + WmWindow::Get(window)->GetWindowState()->set_ignored_by_shelf(true); +} + +void CreateHeaderView(views::Widget* frame, + views::Widget* detached_widget, + Source source) { + HeaderView* header_view = new HeaderView(frame); if (source == Source::CLIENT) { // HeaderView behaves differently when the widget it is associated with is // fullscreen (HeaderView is normally the @@ -42,32 +67,81 @@ // the client HeaderView is not the ImmersiveFullscreenControllerDelegate. header_view->set_is_immersive_delegate(false); } - widget_->SetContentsView(header_view); - widget_->GetRootView()->SetSize(bounds.size()); - widget_->ShowInactive(); + header_view->set_is_immersive_delegate(false); + detached_widget->SetContentsView(header_view); } -void DetachedTitleAreaRenderer::Destroy() { - host_ = nullptr; - if (widget_) - widget_->CloseNow(); +} // namespace + +DetachedTitleAreaRendererForInternal::DetachedTitleAreaRendererForInternal( + views::Widget* frame) + : widget_(base::MakeUnique<views::Widget>()) { + std::unique_ptr<views::Widget::InitParams> params = + CreateInitParams("DetachedTitleAreaRendererForInternal"); + params->ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params->parent = frame->GetNativeView()->parent(); + widget_->Init(*params); + aura::client::GetTransientWindowClient()->AddTransientChild( + frame->GetNativeView(), widget_->GetNativeView()); + CreateHeaderView(frame, widget_.get(), Source::INTERNAL); + ConfigureCommonWidgetProperties(widget_.get()); } -views::Widget* DetachedTitleAreaRenderer::GetWidget() { +DetachedTitleAreaRendererForInternal::~DetachedTitleAreaRendererForInternal() {} + +DetachedTitleAreaRendererForClient::DetachedTitleAreaRendererForClient( + aura::Window* parent, + std::map<std::string, std::vector<uint8_t>>* properties, + WindowManager* window_manager) + : widget_(new views::Widget) { + std::unique_ptr<views::Widget::InitParams> params = + CreateInitParams("DetachedTitleAreaRendererForClient"); + views::NativeWidgetAura* native_widget = + new views::NativeWidgetAura(widget_, true); + aura::SetWindowType(native_widget->GetNativeWindow(), + ui::mojom::WindowType::POPUP); + ApplyProperties(native_widget->GetNativeWindow(), + window_manager->property_converter(), *properties); + native_widget->GetNativeView()->SetProperty(kDetachedTitleAreaRendererKey, + this); + params->delegate = this; + params->native_widget = native_widget; + params->parent = parent; + widget_->Init(*params); + ConfigureCommonWidgetProperties(widget_); +} + +// static +DetachedTitleAreaRendererForClient* +DetachedTitleAreaRendererForClient::ForWindow(aura::Window* window) { + return window->GetProperty(kDetachedTitleAreaRendererKey); +} + +void DetachedTitleAreaRendererForClient::Attach(views::Widget* frame) { + DCHECK(!is_attached_); + is_attached_ = true; + CreateHeaderView(frame, widget_, Source::CLIENT); + frame->GetNativeView()->parent()->AddChild(widget_->GetNativeView()); +} + +void DetachedTitleAreaRendererForClient::Detach() { + is_attached_ = false; + widget_->SetContentsView(new views::View()); +} + +views::Widget* DetachedTitleAreaRendererForClient::GetWidget() { return widget_; } -const views::Widget* DetachedTitleAreaRenderer::GetWidget() const { +const views::Widget* DetachedTitleAreaRendererForClient::GetWidget() const { return widget_; } -void DetachedTitleAreaRenderer::DeleteDelegate() { - if (host_) - host_->OnDetachedTitleAreaRendererDestroyed(this); +void DetachedTitleAreaRendererForClient::DeleteDelegate() { delete this; } -DetachedTitleAreaRenderer::~DetachedTitleAreaRenderer() {} +DetachedTitleAreaRendererForClient::~DetachedTitleAreaRendererForClient() {} } // namespace mus } // namespace ash
diff --git a/ash/mus/frame/detached_title_area_renderer.h b/ash/mus/frame/detached_title_area_renderer.h index b222df53..f82fe3e1 100644 --- a/ash/mus/frame/detached_title_area_renderer.h +++ b/ash/mus/frame/detached_title_area_renderer.h
@@ -5,41 +5,72 @@ #ifndef ASH_MUS_FRAME_DETACHED_TITLE_AREA_RENDERER_H_ #define ASH_MUS_FRAME_DETACHED_TITLE_AREA_RENDERER_H_ +#include <stdint.h> + +#include <map> +#include <string> +#include <vector> + #include "base/macros.h" #include "ui/views/widget/widget_delegate.h" +namespace aura { +class Window; +} + namespace ash { + namespace mus { -class DetachedTitleAreaRendererHost; +class WindowManager; // DetachedTitleAreaRenderer contains a HeaderView in a widget. It's intended to // be used when the title area needs to be rendered in a window different from // the normal window the title area renders to (such as in immersive mode). -class DetachedTitleAreaRenderer : public views::WidgetDelegate { +// +// DetachedTitleAreaRenderer comes in two variants. +// DetachedTitleAreaRendererForClient is used for clients that need to draw +// into the non-client area of the widget. For example, Chrome browser windows +// draw into the non-client area of tabbed browser widgets (the tab strip +// is in the non-client area). In such a case +// DetachedTitleAreaRendererForClient is used. +// If the client does not need to draw to the non-client area then +// DetachedTitleAreaRendererInternal is used (and ash controls the whole +// immersive experience). Which is used is determined by +// |kRenderParentTitleArea_Property|. If |kRenderParentTitleArea_Property| is +// false DetachedTitleAreaRendererInternal is used. + +// DetachedTitleAreaRendererInternal owns the widget it creates. +class DetachedTitleAreaRendererForInternal { public: - // Used to indicate why this is being created. - enum class Source { - // This is being created at the request of a client, specifically because - // of kRenderParentTitleArea_Property set on a client owned window. - CLIENT, + // |frame| is the Widget the decorations are configured from. + explicit DetachedTitleAreaRendererForInternal(views::Widget* frame); + ~DetachedTitleAreaRendererForInternal(); - // Mash is creating this class to host an immersive reveal. Note that CLIENT - // is also likely used for an immersive reveal, but for CLIENT the client - // is completely controlling the reveal and not mash. In other words for - // CLIENT ImmersiveFullscreenController is not running in mash. - MASH, - }; + views::Widget* widget() { return widget_.get(); } - // Creates a widget to render the title area and shows it. |frame| is the - // widget whose frame state is rendered to. This object is deleted explicitly - // by calling Destroy(). - DetachedTitleAreaRenderer(DetachedTitleAreaRendererHost* host, - views::Widget* frame, - const gfx::Rect& bounds, - Source source); + private: + std::unique_ptr<views::Widget> widget_; - void Destroy(); + DISALLOW_COPY_AND_ASSIGN(DetachedTitleAreaRendererForInternal); +}; + +// Used when the client wants to control, and possibly render to, the widget +// hosting the frame decorations. In this mode the client owns the window +// backing the widget and controls the lifetime of the window. +class DetachedTitleAreaRendererForClient : public views::WidgetDelegate { + public: + DetachedTitleAreaRendererForClient( + aura::Window* parent, + std::map<std::string, std::vector<uint8_t>>* properties, + WindowManager* window_manager); + + static DetachedTitleAreaRendererForClient* ForWindow(aura::Window* window); + + void Attach(views::Widget* frame); + void Detach(); + + bool is_attached() const { return is_attached_; } views::Widget* widget() { return widget_; } @@ -49,13 +80,14 @@ void DeleteDelegate() override; private: - ~DetachedTitleAreaRenderer() override; + ~DetachedTitleAreaRendererForClient() override; - DetachedTitleAreaRendererHost* host_; - views::Widget* frame_; views::Widget* widget_; - DISALLOW_COPY_AND_ASSIGN(DetachedTitleAreaRenderer); + // Has Attach() been called? + bool is_attached_ = false; + + DISALLOW_COPY_AND_ASSIGN(DetachedTitleAreaRendererForClient); }; } // namespace mus
diff --git a/ash/mus/frame/detached_title_area_renderer_host.h b/ash/mus/frame/detached_title_area_renderer_host.h deleted file mode 100644 index 416c028..0000000 --- a/ash/mus/frame/detached_title_area_renderer_host.h +++ /dev/null
@@ -1,27 +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 ASH_MUS_FRAME_DETATCHED_TITLE_AREA_RENDERER_HOST_H_ -#define ASH_MUS_FRAME_DETATCHED_TITLE_AREA_RENDERER_HOST_H_ - -namespace ash { -namespace mus { - -class DetachedTitleAreaRenderer; - -// Used to inform the creator of DetachedTitleAreaRenderer of interesting -// events. -class DetachedTitleAreaRendererHost { - public: - virtual void OnDetachedTitleAreaRendererDestroyed( - DetachedTitleAreaRenderer* renderer) = 0; - - protected: - virtual ~DetachedTitleAreaRendererHost() {} -}; - -} // namespace mus -} // namespace ash - -#endif // ASH_MUS_FRAME_DETATCHED_TITLE_AREA_RENDERER_HOST_H_
diff --git a/ash/mus/non_client_frame_controller.cc b/ash/mus/non_client_frame_controller.cc index e14f4c9..e57377b 100644 --- a/ash/mus/non_client_frame_controller.cc +++ b/ash/mus/non_client_frame_controller.cc
@@ -29,6 +29,7 @@ #include "base/strings/utf_string_conversions.h" #include "services/ui/public/interfaces/window_manager.mojom.h" #include "ui/aura/client/aura_constants.h" +#include "ui/aura/client/transient_window_client.h" #include "ui/aura/mus/property_converter.h" #include "ui/aura/mus/property_utils.h" #include "ui/aura/mus/window_manager_delegate.h" @@ -79,8 +80,7 @@ // top container contains a DetachedTitleAreaRenderer, which handles drawing and // events. class ImmersiveFullscreenControllerDelegateMus - : public ImmersiveFullscreenControllerDelegate, - public DetachedTitleAreaRendererHost { + : public ImmersiveFullscreenControllerDelegate { public: ImmersiveFullscreenControllerDelegateMus(views::Widget* frame, aura::Window* frame_window) @@ -126,12 +126,6 @@ return result; } - // DetachedTitleAreaRendererHost: - void OnDetachedTitleAreaRendererDestroyed( - DetachedTitleAreaRenderer* renderer) override { - title_area_renderer_ = nullptr; - } - private: void CreateTitleAreaWindow() { if (GetTitleAreaWindow()) @@ -144,16 +138,13 @@ bounds.set_height( NonClientFrameController::GetPreferredClientAreaInsets().top()); bounds.set_y(bounds.y() - bounds.height()); - title_area_renderer_ = new DetachedTitleAreaRenderer( - this, frame_, bounds, DetachedTitleAreaRenderer::Source::MASH); + title_area_renderer_ = + base::MakeUnique<DetachedTitleAreaRendererForInternal>(frame_); + title_area_renderer_->widget()->SetBounds(bounds); + title_area_renderer_->widget()->ShowInactive(); } - void DestroyTitleAreaWindow() { - if (!GetTitleAreaWindow()) - return; - title_area_renderer_->Destroy(); - title_area_renderer_ = nullptr; - } + void DestroyTitleAreaWindow() { title_area_renderer_.reset(); } aura::Window* GetTitleAreaWindow() { return const_cast<aura::Window*>( @@ -172,7 +163,7 @@ // The ui::Window associated with |frame_|. aura::Window* frame_window_; - DetachedTitleAreaRenderer* title_area_renderer_ = nullptr; + std::unique_ptr<DetachedTitleAreaRendererForInternal> title_area_renderer_; DISALLOW_COPY_AND_ASSIGN(ImmersiveFullscreenControllerDelegateMus); }; @@ -336,6 +327,8 @@ : gfx::Insets(); window_manager_client_->SetUnderlaySurfaceOffsetAndExtendedHitArea( window_, gfx::Vector2d(shadow_inset, shadow_inset), extended_hit_region); + + aura::client::GetTransientWindowClient()->AddObserver(this); } // static @@ -369,16 +362,9 @@ } NonClientFrameController::~NonClientFrameController() { + aura::client::GetTransientWindowClient()->RemoveObserver(this); if (window_) window_->RemoveObserver(this); - if (detached_title_area_renderer_) - detached_title_area_renderer_->Destroy(); -} - -void NonClientFrameController::OnDetachedTitleAreaRendererDestroyed( - DetachedTitleAreaRenderer* renderer) { - DCHECK_EQ(detached_title_area_renderer_, renderer); - detached_title_area_renderer_ = nullptr; } base::string16 NonClientFrameController::GetWindowTitle() const { @@ -416,21 +402,6 @@ return new ClientViewMus(widget, GetContentsView(), this); } -void NonClientFrameController::OnWindowHierarchyChanged( - const HierarchyChangeParams& params) { - if (params.new_parent != window_ || - !params.target->GetProperty(kRenderTitleAreaProperty)) { - return; - } - if (detached_title_area_renderer_) { - detached_title_area_renderer_->Destroy(); - detached_title_area_renderer_ = nullptr; - } - detached_title_area_renderer_ = - new DetachedTitleAreaRenderer(this, widget_, params.target->bounds(), - DetachedTitleAreaRenderer::Source::CLIENT); -} - void NonClientFrameController::OnWindowPropertyChanged(aura::Window* window, const void* key, intptr_t old) { @@ -455,5 +426,41 @@ window_ = nullptr; } +void NonClientFrameController::OnTransientChildWindowAdded( + aura::Window* parent, + aura::Window* transient_child) { + if (parent != window_ || + !transient_child->GetProperty(kRenderTitleAreaProperty)) { + return; + } + + DetachedTitleAreaRendererForClient* renderer = + DetachedTitleAreaRendererForClient::ForWindow(transient_child); + if (!renderer || renderer->is_attached()) + return; + + renderer->Attach(widget_); +} + +void NonClientFrameController::OnTransientChildWindowRemoved( + aura::Window* parent, + aura::Window* transient_child) { + if (parent != window_) + return; + + DetachedTitleAreaRendererForClient* renderer = + DetachedTitleAreaRendererForClient::ForWindow(transient_child); + if (renderer) + renderer->Detach(); +} + +void NonClientFrameController::OnWillRestackTransientChildAbove( + aura::Window* parent, + aura::Window* transient_child) {} + +void NonClientFrameController::OnDidRestackTransientChildAbove( + aura::Window* parent, + aura::Window* transient_child) {} + } // namespace mus } // namespace ash
diff --git a/ash/mus/non_client_frame_controller.h b/ash/mus/non_client_frame_controller.h index dcacc1dc..00c3808 100644 --- a/ash/mus/non_client_frame_controller.h +++ b/ash/mus/non_client_frame_controller.h
@@ -11,9 +11,9 @@ #include <string> #include <vector> -#include "ash/mus/frame/detached_title_area_renderer_host.h" #include "base/macros.h" #include "base/strings/string16.h" +#include "ui/aura/client/transient_window_client_observer.h" #include "ui/aura/window_observer.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/rect.h" @@ -40,9 +40,10 @@ class WindowManager; // Provides the non-client frame for mus Windows. -class NonClientFrameController : public views::WidgetDelegateView, - public aura::WindowObserver, - public DetachedTitleAreaRendererHost { +class NonClientFrameController + : public views::WidgetDelegateView, + public aura::WindowObserver, + public aura::client::TransientWindowClientObserver { public: // Creates a new NonClientFrameController and window to render the non-client // frame decorations. This deletes itself when |window| is destroyed. |parent| @@ -80,10 +81,6 @@ private: ~NonClientFrameController() override; - // DetachedTitleAreaRendererHost: - void OnDetachedTitleAreaRendererDestroyed( - DetachedTitleAreaRenderer* renderer) override; - // views::WidgetDelegateView: base::string16 GetWindowTitle() const override; bool CanResize() const override; @@ -93,12 +90,21 @@ views::ClientView* CreateClientView(views::Widget* widget) override; // aura::WindowObserver: - void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override; void OnWindowPropertyChanged(aura::Window* window, const void* key, intptr_t old) override; void OnWindowDestroyed(aura::Window* window) override; + // aura::client::TransientWindowClientObserver: + void OnTransientChildWindowAdded(aura::Window* parent, + aura::Window* transient_child) override; + void OnTransientChildWindowRemoved(aura::Window* parent, + aura::Window* transient_child) override; + void OnWillRestackTransientChildAbove(aura::Window* parent, + aura::Window* transient_child) override; + void OnDidRestackTransientChildAbove(aura::Window* parent, + aura::Window* transient_child) override; + aura::WindowManagerClient* window_manager_client_; views::Widget* widget_; @@ -107,10 +113,6 @@ // is null. aura::Window* window_; - // Used if a child window is added that has the - // kRenderParentTitleArea_Property set. - DetachedTitleAreaRenderer* detached_title_area_renderer_ = nullptr; - bool did_init_native_widget_ = false; gfx::Insets client_area_insets_;
diff --git a/ash/mus/property_util.cc b/ash/mus/property_util.cc index 44e7121..0ebcc0b 100644 --- a/ash/mus/property_util.cc +++ b/ash/mus/property_util.cc
@@ -6,6 +6,8 @@ #include "services/ui/public/cpp/property_type_converters.h" #include "services/ui/public/interfaces/window_manager.mojom.h" +#include "ui/aura/mus/property_converter.h" +#include "ui/aura/window.h" #include "ui/display/types/display_constants.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -62,5 +64,15 @@ return iter == properties.end() || !mojo::ConvertTo<bool>(iter->second); } +void ApplyProperties( + aura::Window* window, + aura::PropertyConverter* property_converter, + const std::map<std::string, std::vector<uint8_t>>& properties) { + for (auto& property_pair : properties) { + property_converter->SetPropertyFromTransportValue( + window, property_pair.first, &property_pair.second); + } +} + } // namespace mus } // namespace ash
diff --git a/ash/mus/property_util.h b/ash/mus/property_util.h index beb6886..5078b463 100644 --- a/ash/mus/property_util.h +++ b/ash/mus/property_util.h
@@ -11,11 +11,22 @@ #include <string> #include <vector> +namespace aura { +class PropertyConverter; +class Window; +} + namespace gfx { class Rect; class Size; } +namespace ui { +namespace mojom { +enum class WindowType; +} +} + namespace ash { namespace mus { @@ -48,6 +59,12 @@ bool ShouldEnableImmersive(const InitProperties& properties); +// Applies |properties| to |window| using |property_converter|. +void ApplyProperties( + aura::Window* window, + aura::PropertyConverter* property_converter, + const std::map<std::string, std::vector<uint8_t>>& properties); + } // namespace mus } // namespace ash
diff --git a/ash/mus/top_level_window_factory.cc b/ash/mus/top_level_window_factory.cc index 5da13441..1eb88d9 100644 --- a/ash/mus/top_level_window_factory.cc +++ b/ash/mus/top_level_window_factory.cc
@@ -9,6 +9,7 @@ #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/mus/disconnected_app_handler.h" +#include "ash/mus/frame/detached_title_area_renderer.h" #include "ash/mus/non_client_frame_controller.h" #include "ash/mus/property_util.h" #include "ash/mus/window_manager.h" @@ -40,6 +41,21 @@ ui::SHOW_STATE_FULLSCREEN); } +bool ShouldRenderTitleArea( + aura::PropertyConverter* property_converter, + const std::map<std::string, std::vector<uint8_t>>& properties) { + auto iter = properties.find( + ui::mojom::WindowManager::kRenderParentTitleArea_Property); + if (iter == properties.end()) + return false; + + aura::PropertyConverter::PrimitiveType value = 0; + return property_converter->GetPropertyValueFromTransportValue( + ui::mojom::WindowManager::kRenderParentTitleArea_Property, + iter->second, &value) && + value == 1; +} + // Returns the RootWindowController where new top levels are created. // |properties| is the properties supplied during window creation. RootWindowController* GetRootWindowControllerForNewTopLevelWindow( @@ -135,16 +151,27 @@ return non_client_frame_controller->window(); } - aura::Window* window = new aura::Window(nullptr); - aura::SetWindowType(window, window_type); - // Apply properties before Init(), that way they are sent to the server at - // the time the window is created. aura::PropertyConverter* property_converter = window_manager->property_converter(); - for (auto& property_pair : *properties) { - property_converter->SetPropertyFromTransportValue( - window, property_pair.first, &property_pair.second); + + if (window_type == ui::mojom::WindowType::POPUP && + ShouldRenderTitleArea(property_converter, *properties)) { + // Pick a parent so display information is obtained. Will pick the real one + // once transient parent found. + aura::Window* unparented_control_container = + root_window_controller->GetWindow() + ->GetChildByShellWindowId(kShellWindowId_UnparentedControlContainer) + ->aura_window(); + // DetachedTitleAreaRendererForClient is owned by the client. + DetachedTitleAreaRendererForClient* renderer = + new DetachedTitleAreaRendererForClient(unparented_control_container, + properties, window_manager); + return renderer->widget()->GetNativeView(); } + + aura::Window* window = new aura::Window(nullptr); + aura::SetWindowType(window, window_type); + ApplyProperties(window, property_converter, *properties); window->Init(ui::LAYER_TEXTURED); window->SetBounds(bounds);
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn index baae1f0..c0d2536f 100644 --- a/ash/public/cpp/BUILD.gn +++ b/ash/public/cpp/BUILD.gn
@@ -9,6 +9,8 @@ "mus_property_mirror_ash.cc", "mus_property_mirror_ash.h", "session_types.h", + "shelf_application_menu_item.cc", + "shelf_application_menu_item.h", "shelf_types.h", "shell_window_ids.cc", "shell_window_ids.h",
diff --git a/ash/public/cpp/shelf_application_menu_item.cc b/ash/public/cpp/shelf_application_menu_item.cc new file mode 100644 index 0000000..77550c9 --- /dev/null +++ b/ash/public/cpp/shelf_application_menu_item.cc
@@ -0,0 +1,17 @@ +// 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 "ash/public/cpp/shelf_application_menu_item.h" + +namespace ash { + +ShelfApplicationMenuItem::ShelfApplicationMenuItem(const base::string16 title, + const gfx::Image* icon) + : title_(title), icon_(icon ? gfx::Image(*icon) : gfx::Image()) {} + +ShelfApplicationMenuItem::~ShelfApplicationMenuItem() {} + +void ShelfApplicationMenuItem::Execute(int event_flags) {} + +} // namespace ash
diff --git a/ash/public/cpp/shelf_application_menu_item.h b/ash/public/cpp/shelf_application_menu_item.h new file mode 100644 index 0000000..f2d7e53 --- /dev/null +++ b/ash/public/cpp/shelf_application_menu_item.h
@@ -0,0 +1,46 @@ +// 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 ASH_PUBLIC_CPP_SHELF_APPLICATION_MENU_ITEM_H_ +#define ASH_PUBLIC_CPP_SHELF_APPLICATION_MENU_ITEM_H_ + +#include <memory> +#include <vector> + +#include "ash/public/cpp/ash_public_export.h" +#include "base/macros.h" +#include "base/strings/string16.h" +#include "ui/gfx/image/image.h" + +namespace ash { + +// The title, icon, and execute function for shelf application menu items. +class ASH_PUBLIC_EXPORT ShelfApplicationMenuItem { + public: + // Creates an item with a |title| and optional |icon| (pass nullptr for none). + explicit ShelfApplicationMenuItem(const base::string16 title, + const gfx::Image* icon = nullptr); + virtual ~ShelfApplicationMenuItem(); + + // The title and icon for this menu item. + const base::string16& title() const { return title_; } + const gfx::Image& icon() const { return icon_; } + + // Executes the menu item; |event_flags| can be used to check additional + // keyboard modifiers from the event that issued this command. + virtual void Execute(int event_flags); + + private: + const base::string16 title_; + const gfx::Image icon_; + + DISALLOW_COPY_AND_ASSIGN(ShelfApplicationMenuItem); +}; + +using ShelfAppMenuItemList = + std::vector<std::unique_ptr<ShelfApplicationMenuItem>>; + +} // namespace ash + +#endif // ASH_PUBLIC_CPP_SHELF_APPLICATION_MENU_ITEM_H_
diff --git a/ash/resources/ash_resources.grd b/ash/resources/ash_resources.grd index 31f18c9..4572f5b 100644 --- a/ash/resources/ash_resources.grd +++ b/ash/resources/ash_resources.grd
@@ -65,10 +65,6 @@ <structure type="chrome_scaled_image" name="IDR_AURA_TRAY_BG_VERTICAL_PRESSED_CENTER" file="common/shelf/status_tray_vertical_pressed_center.png" /> <structure type="chrome_scaled_image" name="IDR_AURA_TRAY_BG_VERTICAL_PRESSED_TOP" file="common/shelf/status_tray_vertical_pressed_top.png" /> <structure type="chrome_scaled_image" name="IDR_AURA_TRAY_BG_VERTICAL_TOP" file="common/shelf/status_tray_vertical_normal_top.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_TRAY_POPUP_LABEL_BUTTON_BORDER" file="common/tray_popup_label_button_border.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_TRAY_POPUP_LABEL_BUTTON_HOVER_BACKGROUND" file="common/tray_popup_label_button_hover_background.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND" file="common/tray_popup_label_button_normal_background.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER" file="common/tray_popup_public_account_logout_button_border.png" /> <structure type="chrome_scaled_image" name="IDR_AURA_WARNING_ICON" file="common/alert_small.png" /> @@ -165,24 +161,6 @@ <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_CELLULAR_ENABLED_HOVER" file="cros/network/status_cellular_enabled_hover.png" /> <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_CHILD_USER" file="cros/status/status_child_user.png" /> <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_ENTERPRISE" file="cros/status/status_managed.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_BOTTOM" file="cros/status/status_logout_button_normal_bottom.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_BOTTOM_LEFT" file="cros/status/status_logout_button_normal_bottom_left.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_BOTTOM_RIGHT" file="cros/status/status_logout_button_normal_bottom_right.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_CENTER" file="cros/status/status_logout_button_normal_center.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_LEFT" file="cros/status/status_logout_button_normal_left.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_RIGHT" file="cros/status/status_logout_button_normal_right.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_TOP" file="cros/status/status_logout_button_normal_top.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_TOP_LEFT" file="cros/status/status_logout_button_normal_top_left.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_TOP_RIGHT" file="cros/status/status_logout_button_normal_top_right.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_BOTTOM" file="cros/status/status_logout_button_pushed_bottom.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_BOTTOM_LEFT" file="cros/status/status_logout_button_pushed_bottom_left.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_BOTTOM_RIGHT" file="cros/status/status_logout_button_pushed_bottom_right.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_CENTER" file="cros/status/status_logout_button_pushed_center.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_LEFT" file="cros/status/status_logout_button_pushed_left.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_RIGHT" file="cros/status/status_logout_button_pushed_right.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_TOP" file="cros/status/status_logout_button_pushed_top.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_TOP_LEFT" file="cros/status/status_logout_button_pushed_top_left.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_TOP_RIGHT" file="cros/status/status_logout_button_pushed_top_right.png" /> <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_SUPERVISED_USER" file="cros/status/status_managed_mode_user.png" /> <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_NETWORK_INFO" file="cros/network/status_network_info.png" /> <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_NETWORK_INFO_HOVER" file="cros/network/status_network_info_hover.png" />
diff --git a/ash/resources/default_100_percent/common/tray_popup_label_button_border.png b/ash/resources/default_100_percent/common/tray_popup_label_button_border.png deleted file mode 100644 index 6677ed9..0000000 --- a/ash/resources/default_100_percent/common/tray_popup_label_button_border.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/common/tray_popup_label_button_hover_background.png b/ash/resources/default_100_percent/common/tray_popup_label_button_hover_background.png deleted file mode 100644 index 7c0d12d0..0000000 --- a/ash/resources/default_100_percent/common/tray_popup_label_button_hover_background.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/common/tray_popup_label_button_normal_background.png b/ash/resources/default_100_percent/common/tray_popup_label_button_normal_background.png deleted file mode 100644 index 22d48a8f..0000000 --- a/ash/resources/default_100_percent/common/tray_popup_label_button_normal_background.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/common/tray_popup_public_account_logout_button_border.png b/ash/resources/default_100_percent/common/tray_popup_public_account_logout_button_border.png deleted file mode 100644 index 59c31d64..0000000 --- a/ash/resources/default_100_percent/common/tray_popup_public_account_logout_button_border.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_bottom.png b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_bottom.png deleted file mode 100644 index ec3dd966..0000000 --- a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_bottom.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_bottom_left.png b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_bottom_left.png deleted file mode 100644 index 0dcfba3..0000000 --- a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_bottom_left.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_bottom_right.png b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_bottom_right.png deleted file mode 100644 index ae9f85dc..0000000 --- a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_bottom_right.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_center.png b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_center.png deleted file mode 100644 index 2db34550..0000000 --- a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_center.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_left.png b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_left.png deleted file mode 100644 index a81413a..0000000 --- a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_left.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_right.png b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_right.png deleted file mode 100644 index a23584b..0000000 --- a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_right.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_top.png b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_top.png deleted file mode 100644 index 398908a0..0000000 --- a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_top.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_top_left.png b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_top_left.png deleted file mode 100644 index 29cccfdb..0000000 --- a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_top_left.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_top_right.png b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_top_right.png deleted file mode 100644 index 6a49c25..0000000 --- a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_top_right.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_bottom.png b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_bottom.png deleted file mode 100644 index 4bbc45e..0000000 --- a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_bottom.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_bottom_left.png b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_bottom_left.png deleted file mode 100644 index b270911..0000000 --- a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_bottom_left.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_bottom_right.png b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_bottom_right.png deleted file mode 100644 index 615270b..0000000 --- a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_bottom_right.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_center.png b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_center.png deleted file mode 100644 index 0e49074f..0000000 --- a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_center.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_left.png b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_left.png deleted file mode 100644 index f2e9d48e..0000000 --- a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_left.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_right.png b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_right.png deleted file mode 100644 index 7801a78..0000000 --- a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_right.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_top.png b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_top.png deleted file mode 100644 index 41eaeb0..0000000 --- a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_top.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_top_left.png b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_top_left.png deleted file mode 100644 index 45e5e93..0000000 --- a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_top_left.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_top_right.png b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_top_right.png deleted file mode 100644 index 7dccf38..0000000 --- a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_top_right.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/common/tray_popup_label_button_border.png b/ash/resources/default_200_percent/common/tray_popup_label_button_border.png deleted file mode 100644 index 53588445..0000000 --- a/ash/resources/default_200_percent/common/tray_popup_label_button_border.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/common/tray_popup_label_button_hover_background.png b/ash/resources/default_200_percent/common/tray_popup_label_button_hover_background.png deleted file mode 100644 index 1394880..0000000 --- a/ash/resources/default_200_percent/common/tray_popup_label_button_hover_background.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/common/tray_popup_label_button_normal_background.png b/ash/resources/default_200_percent/common/tray_popup_label_button_normal_background.png deleted file mode 100644 index b6bb158..0000000 --- a/ash/resources/default_200_percent/common/tray_popup_label_button_normal_background.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/common/tray_popup_public_account_logout_button_border.png b/ash/resources/default_200_percent/common/tray_popup_public_account_logout_button_border.png deleted file mode 100644 index 1968364..0000000 --- a/ash/resources/default_200_percent/common/tray_popup_public_account_logout_button_border.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_bottom.png b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_bottom.png deleted file mode 100644 index 84220a8..0000000 --- a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_bottom.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_bottom_left.png b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_bottom_left.png deleted file mode 100644 index 1915157..0000000 --- a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_bottom_left.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_bottom_right.png b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_bottom_right.png deleted file mode 100644 index 149b4a9..0000000 --- a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_bottom_right.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_center.png b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_center.png deleted file mode 100644 index 04ebd60..0000000 --- a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_center.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_left.png b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_left.png deleted file mode 100644 index 706caf6..0000000 --- a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_left.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_right.png b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_right.png deleted file mode 100644 index aab4b068..0000000 --- a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_right.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_top.png b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_top.png deleted file mode 100644 index b813452..0000000 --- a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_top.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_top_left.png b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_top_left.png deleted file mode 100644 index 5480869..0000000 --- a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_top_left.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_top_right.png b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_top_right.png deleted file mode 100644 index bf15dcde..0000000 --- a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_top_right.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_bottom.png b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_bottom.png deleted file mode 100644 index eaf9725..0000000 --- a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_bottom.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_bottom_left.png b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_bottom_left.png deleted file mode 100644 index 79f2792..0000000 --- a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_bottom_left.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_bottom_right.png b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_bottom_right.png deleted file mode 100644 index d6aa1a4..0000000 --- a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_bottom_right.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_center.png b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_center.png deleted file mode 100644 index 90845f6..0000000 --- a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_center.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_left.png b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_left.png deleted file mode 100644 index cb5a7bbe..0000000 --- a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_left.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_right.png b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_right.png deleted file mode 100644 index ce67a6c..0000000 --- a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_right.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_top.png b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_top.png deleted file mode 100644 index adbde7a4..0000000 --- a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_top.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_top_left.png b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_top_left.png deleted file mode 100644 index 14fd3a9..0000000 --- a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_top_left.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_top_right.png b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_top_right.png deleted file mode 100644 index 5d5f634..0000000 --- a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_top_right.png +++ /dev/null Binary files differ
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn index 345f17a..cf3cee47 100644 --- a/ash/resources/vector_icons/BUILD.gn +++ b/ash/resources/vector_icons/BUILD.gn
@@ -2,10 +2,10 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -action("aggregate_vector_icons") { - visibility = [ ":*" ] +import("//ui/vector_icons/vector_icons.gni") - script = "//ui/gfx/vector_icons/aggregate_vector_icons.py" +aggregate_vector_icons("ash_vector_icons") { + icon_directory = "." icons = [ "ime_menu_emoticon.1x.icon", @@ -224,36 +224,14 @@ "window_control_right_snapped.1x.icon", "window_control_right_snapped.icon", ] - - output_cc = "$target_gen_dir/vector_icons.cc" - output_h = "$target_gen_dir/vector_icons.h" - - inputs = icons - inputs += [ - "vector_icons.cc.template", - "vector_icons.h.template", - ] - outputs = [ - output_cc, - output_h, - ] - - response_file_contents = rebase_path(icons, root_build_dir) - - args = [ - "--working_directory=" + rebase_path("./"), - "--file_list={{response_file_name}}", - "--output_cc=" + rebase_path(output_cc, root_build_dir), - "--output_h=" + rebase_path(output_h, root_build_dir), - ] } source_set("vector_icons") { - sources = get_target_outputs(":aggregate_vector_icons") + sources = get_target_outputs(":ash_vector_icons") sources += [ "//ui/gfx/vector_icon_types.h" ] deps = [ - ":aggregate_vector_icons", + ":ash_vector_icons", "//base", "//skia", ]
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc index e2df5ff..62f000f8 100644 --- a/ash/shelf/shelf_view_unittest.cc +++ b/ash/shelf/shelf_view_unittest.cc
@@ -2004,36 +2004,6 @@ DISALLOW_COPY_AND_ASSIGN(InkDropSpy); }; -// A menu model that contains minimum number of items needed for a menu to be -// shown on a shelf item. -class TestShelfMenuModel : public ui::SimpleMenuModel, - public ui::SimpleMenuModel::Delegate { - public: - TestShelfMenuModel() : ui::SimpleMenuModel(this) { Build(); } - ~TestShelfMenuModel() override {} - - private: - void Build() { - // A menu is expected to have at least 6 items. Three spacing separators, - // one title, and at least two more items. - AddSeparator(ui::SPACING_SEPARATOR); - AddItem(0, base::ASCIIToUTF16("Title")); - AddSeparator(ui::SPACING_SEPARATOR); - AddItem(1, base::ASCIIToUTF16("Item 1")); - AddItem(2, base::ASCIIToUTF16("Item 2")); - AddSeparator(ui::SPACING_SEPARATOR); - } - - // ui::SimpleMenuModel::Delegate: - bool IsCommandIdChecked(int command_id) const override { return false; } - bool IsCommandIdEnabled(int command_id) const override { - return command_id != 0; - } - void ExecuteCommand(int command_id, int event_flags) override {} - - DISALLOW_COPY_AND_ASSIGN(TestShelfMenuModel); -}; - // A ShelfItemDelegate that returns a menu for the shelf item. class ListMenuShelfItemDelegate : public TestShelfItemDelegate { public: @@ -2042,8 +2012,12 @@ private: // TestShelfItemDelegate: - ui::SimpleMenuModel* CreateApplicationMenu(int event_flags) override { - return new TestShelfMenuModel; + ShelfAppMenuItemList GetAppMenuItems(int event_flags) override { + ShelfAppMenuItemList items; + base::string16 title = base::ASCIIToUTF16("title"); + items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(title)); + items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(title)); + return items; } DISALLOW_COPY_AND_ASSIGN(ListMenuShelfItemDelegate);
diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc index 277b23e6..28e5e2da 100644 --- a/ash/shell/shell_delegate_impl.cc +++ b/ash/shell/shell_delegate_impl.cc
@@ -44,8 +44,6 @@ } void CreateNote() override {} bool HasNoteApp() override { return false; } - void SetStylusStateChangedCallback( - const OnStylusStateChangedCallback& on_stylus_state_changed) override {} bool ShouldAutoOpenPalette() override { return false; } bool ShouldShowPalette() override { return false; } void TakeScreenshot() override {}
diff --git a/ash/shell/window_watcher_shelf_item_delegate.cc b/ash/shell/window_watcher_shelf_item_delegate.cc index cfceb3c..935186d5 100644 --- a/ash/shell/window_watcher_shelf_item_delegate.cc +++ b/ash/shell/window_watcher_shelf_item_delegate.cc
@@ -31,9 +31,10 @@ return kExistingWindowActivated; } -ui::SimpleMenuModel* WindowWatcherShelfItemDelegate::CreateApplicationMenu( +ShelfAppMenuItemList WindowWatcherShelfItemDelegate::GetAppMenuItems( int event_flags) { - return nullptr; + // Return an empty item list to avoid showing an application menu. + return ShelfAppMenuItemList(); } void WindowWatcherShelfItemDelegate::Close() {}
diff --git a/ash/shell/window_watcher_shelf_item_delegate.h b/ash/shell/window_watcher_shelf_item_delegate.h index b373dd577..b867231 100644 --- a/ash/shell/window_watcher_shelf_item_delegate.h +++ b/ash/shell/window_watcher_shelf_item_delegate.h
@@ -24,7 +24,7 @@ // ShelfItemDelegate: ShelfItemDelegate::PerformedAction ItemSelected( const ui::Event& event) override; - ui::SimpleMenuModel* CreateApplicationMenu(int event_flags) override; + ShelfAppMenuItemList GetAppMenuItems(int event_flags) override; void Close() override; private:
diff --git a/ash/sticky_keys/sticky_keys_overlay.cc b/ash/sticky_keys/sticky_keys_overlay.cc index 9e7e76e..2cbc2f01 100644 --- a/ash/sticky_keys/sticky_keys_overlay.cc +++ b/ash/sticky_keys/sticky_keys_overlay.cc
@@ -157,10 +157,10 @@ StickyKeysOverlayView::~StickyKeysOverlayView() {} void StickyKeysOverlayView::OnPaint(gfx::Canvas* canvas) { - cc::PaintFlags paint; - paint.setStyle(cc::PaintFlags::kFill_Style); - paint.setColor(SkColorSetARGB(0xB3, 0x55, 0x55, 0x55)); - canvas->DrawRoundRect(GetLocalBounds(), 2, paint); + cc::PaintFlags flags; + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setColor(SkColorSetARGB(0xB3, 0x55, 0x55, 0x55)); + canvas->DrawRoundRect(GetLocalBounds(), 2, flags); views::View::OnPaint(canvas); }
diff --git a/ash/touch/touch_hud_debug.cc b/ash/touch/touch_hud_debug.cc index 5f1bfc7..220ee5f 100644 --- a/ash/touch/touch_hud_debug.cc +++ b/ash/touch/touch_hud_debug.cc
@@ -241,7 +241,7 @@ SetPaintToLayer(); layer()->SetFillsBoundsOpaquely(false); - paint_.setStyle(cc::PaintFlags::kFill_Style); + flags_.setStyle(cc::PaintFlags::kFill_Style); } ~TouchHudCanvas() override {} @@ -299,12 +299,12 @@ for (int i = 0; i < kMaxPaths; ++i) { if (paths_[i].countPoints() == 0) continue; - paint_.setColor(colors_[i]); - canvas->DrawPath(paths_[i], paint_); + flags_.setColor(colors_[i]); + canvas->DrawPath(paths_[i], flags_); } } - cc::PaintFlags paint_; + cc::PaintFlags flags_; const TouchLog& touch_log_; SkPath paths_[kMaxPaths];
diff --git a/ash/touch_hud/touch_hud_renderer.cc b/ash/touch_hud/touch_hud_renderer.cc index 9430f08..daedba3 100644 --- a/ash/touch_hud/touch_hud_renderer.cc +++ b/ash/touch_hud/touch_hud_renderer.cc
@@ -40,8 +40,8 @@ SetSize(gfx::Size(2 * kPointRadius + 2, 2 * kPointRadius + 2)); - stroke_paint_.setStyle(cc::PaintFlags::kStroke_Style); - stroke_paint_.setColor(kProjectionStrokeColor); + stroke_flags_.setStyle(cc::PaintFlags::kStroke_Style); + stroke_flags_.setColor(kProjectionStrokeColor); gradient_colors_[0] = kProjectionFillColor; gradient_colors_[1] = kProjectionStrokeColor; @@ -82,16 +82,16 @@ int alpha = kProjectionAlpha; if (fadeout_) alpha = static_cast<int>(fadeout_->CurrentValueBetween(alpha, 0)); - fill_paint_.setAlpha(alpha); - stroke_paint_.setAlpha(alpha); - fill_paint_.setShader(SkGradientShader::MakeRadial( + fill_flags_.setAlpha(alpha); + stroke_flags_.setAlpha(alpha); + fill_flags_.setShader(SkGradientShader::MakeRadial( gradient_center_, SkIntToScalar(kPointRadius), gradient_colors_, gradient_pos_, arraysize(gradient_colors_), SkShader::kMirror_TileMode)); canvas->DrawCircle(circle_center_, SkIntToScalar(kPointRadius), - fill_paint_); + fill_flags_); canvas->DrawCircle(circle_center_, SkIntToScalar(kPointRadius), - stroke_paint_); + stroke_flags_); } // Overridden from gfx::AnimationDelegate. @@ -120,8 +120,8 @@ const gfx::Point circle_center_; const SkPoint gradient_center_; - cc::PaintFlags fill_paint_; - cc::PaintFlags stroke_paint_; + cc::PaintFlags fill_flags_; + cc::PaintFlags stroke_flags_; SkColor gradient_colors_[2]; SkScalar gradient_pos_[2];
diff --git a/ash/utility/screenshot_controller.cc b/ash/utility/screenshot_controller.cc index dc20763..5728596 100644 --- a/ash/utility/screenshot_controller.cc +++ b/ash/utility/screenshot_controller.cc
@@ -160,30 +160,30 @@ if (pseudo_cursor_point.y() == region_.y()) pseudo_cursor_point.Offset(0, -1); - cc::PaintFlags paint; - paint.setAntiAlias(false); - paint.setStrokeWidth(1); - paint.setColor(SK_ColorWHITE); - paint.setBlendMode(SkBlendMode::kSrc); + cc::PaintFlags flags; + flags.setAntiAlias(false); + flags.setStrokeWidth(1); + flags.setColor(SK_ColorWHITE); + flags.setBlendMode(SkBlendMode::kSrc); gfx::Vector2d width(kCursorSize / 2, 0); gfx::Vector2d height(0, kCursorSize / 2); gfx::Vector2d white_x_offset(1, -1); gfx::Vector2d white_y_offset(1, -1); // Horizontal canvas->DrawLine(pseudo_cursor_point - width + white_x_offset, - pseudo_cursor_point + width + white_x_offset, paint); - paint.setStrokeWidth(1); + pseudo_cursor_point + width + white_x_offset, flags); + flags.setStrokeWidth(1); // Vertical canvas->DrawLine(pseudo_cursor_point - height + white_y_offset, - pseudo_cursor_point + height + white_y_offset, paint); + pseudo_cursor_point + height + white_y_offset, flags); - paint.setColor(SK_ColorBLACK); + flags.setColor(SK_ColorBLACK); // Horizontal canvas->DrawLine(pseudo_cursor_point - width, pseudo_cursor_point + width, - paint); + flags); // Vertical canvas->DrawLine(pseudo_cursor_point - height, pseudo_cursor_point + height, - paint); + flags); } bool draw_inactive_overlay_;
diff --git a/base/BUILD.gn b/base/BUILD.gn index fc39018e..99017c74 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -275,6 +275,7 @@ "command_line.h", "compiler_specific.h", "containers/adapters.h", + "containers/flat_set.h", "containers/hash_tables.h", "containers/linked_list.h", "containers/mru_cache.h", @@ -1902,6 +1903,7 @@ "cancelable_callback_unittest.cc", "command_line_unittest.cc", "containers/adapters_unittest.cc", + "containers/flat_set_unittest.cc", "containers/hash_tables_unittest.cc", "containers/linked_list_unittest.cc", "containers/mru_cache_unittest.cc",
diff --git a/base/android/base_jni_onload.cc b/base/android/base_jni_onload.cc index 7ab4982..0a82db4 100644 --- a/base/android/base_jni_onload.cc +++ b/base/android/base_jni_onload.cc
@@ -12,13 +12,11 @@ namespace base { namespace android { -namespace { - -bool RegisterJNI(JNIEnv* env) { +bool OnJNIOnLoadRegisterJNI(JNIEnv* env) { return RegisterLibraryLoaderEntryHook(env); } -bool Init() { +bool OnJNIOnLoadInit() { InitAtExitManager(); JNIEnv* env = base::android::AttachCurrentThread(); base::android::InitReplacementClassLoader(env, @@ -26,32 +24,5 @@ return true; } -} // namespace - - -bool OnJNIOnLoadRegisterJNI(JavaVM* vm, - std::vector<RegisterCallback> callbacks) { - base::android::InitVM(vm); - JNIEnv* env = base::android::AttachCurrentThread(); - - callbacks.push_back(base::Bind(&RegisterJNI)); - for (std::vector<RegisterCallback>::reverse_iterator i = - callbacks.rbegin(); i != callbacks.rend(); ++i) { - if (!i->Run(env)) - return false; - } - return true; -} - -bool OnJNIOnLoadInit(std::vector<InitCallback> callbacks) { - callbacks.push_back(base::Bind(&Init)); - for (std::vector<InitCallback>::reverse_iterator i = - callbacks.rbegin(); i != callbacks.rend(); ++i) { - if (!i->Run()) - return false; - } - return true; -} - } // namespace android } // namespace base
diff --git a/base/android/base_jni_onload.h b/base/android/base_jni_onload.h index dcc7756..be637d5 100644 --- a/base/android/base_jni_onload.h +++ b/base/android/base_jni_onload.h
@@ -14,17 +14,12 @@ namespace base { namespace android { -// Returns whether JNI registration succeeded. Caller shall put the -// RegisterCallback into |callbacks| in reverse order. +// Returns whether JNI registration succeeded. typedef base::Callback<bool(JNIEnv*)> RegisterCallback; -BASE_EXPORT bool OnJNIOnLoadRegisterJNI( - JavaVM* vm, - std::vector<RegisterCallback> callbacks); +BASE_EXPORT bool OnJNIOnLoadRegisterJNI(JNIEnv* env); -// Returns whether initialization succeeded. Caller shall put the -// InitCallback into |callbacks| in reverse order. -typedef base::Callback<bool(void)> InitCallback; -BASE_EXPORT bool OnJNIOnLoadInit(std::vector<InitCallback> callbacks); +// Returns whether initialization succeeded. +BASE_EXPORT bool OnJNIOnLoadInit(); } // namespace android } // namespace base
diff --git a/base/android/record_histogram.cc b/base/android/record_histogram.cc index 5679762e..1a207a18 100644 --- a/base/android/record_histogram.cc +++ b/base/android/record_histogram.cc
@@ -53,12 +53,16 @@ jstring j_histogram_name, int32_t expected_min, int32_t expected_max, - int32_t expected_bucket_count, + uint32_t expected_bucket_count, HistogramBase* histogram) { + std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name); + bool valid_arguments = Histogram::InspectConstructionArguments( + histogram_name, &expected_min, &expected_max, &expected_bucket_count); + DCHECK(valid_arguments); DCHECK(histogram->HasConstructionArguments(expected_min, expected_max, expected_bucket_count)) - << ConvertJavaStringToUTF8(env, j_histogram_name) << "/" << expected_min - << "/" << expected_max << "/" << expected_bucket_count << " vs. " + << histogram_name << "/" << expected_min << "/" << expected_max << "/" + << expected_bucket_count << " vs. " << HistogramConstructionParamsToString(histogram); }
diff --git a/base/containers/flat_set.h b/base/containers/flat_set.h new file mode 100644 index 0000000..21334ebe --- /dev/null +++ b/base/containers/flat_set.h
@@ -0,0 +1,656 @@ +// 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 BASE_CONTAINERS_FLAT_SET_H_ +#define BASE_CONTAINERS_FLAT_SET_H_ + +#include <algorithm> +#include <functional> +#include <utility> +#include <vector> + +namespace base { + +// Overview: +// This file implements flat_set container. It is an alternative to standard +// sorted containers that stores it's elements in contiguous memory (current +// version uses sorted std::vector). +// Discussion that preceded introduction of this container can be found here: +// https://groups.google.com/a/chromium.org/forum/#!searchin/chromium-dev/vector$20based/chromium-dev/4uQMma9vj9w/HaQ-WvMOAwAJ +// +// Motivation: +// Contiguous memory is very beneficial to iteration and copy speed at the cost +// of worse algorithmic complexity of insertion/erasure operations. They can +// be very fast for set operations and for small number of elements. +// +// Usage guidance: +// Prefer base::flat_set for: +// * Very small sets, something that is an easy fit for cache. Consider +// "very small" to be under a 100 32bit integers. +// * Sets that are built once (using flat_set::flat_set(first, last)). Consider +// collecting all data in a vector and then building flat_set out of it. +// TODO(dyaroshev): improve the interface to better support this pattern +// (crbug.com/682254). +// * Sets where mutating happens in big bulks: use erase(std::remove()) idiom +// for erasing many elements. Insertion is harder - consider set operations +// or building a new vector. Set operations can be slow if one of the sets +// is considerably bigger. Also be aware that beating performance of +// sort + unique (implementation of flat_set's constructor) is hard, clever +// merge of many sets might not win. Generally avoid inserting into flat set +// without benchmarks. +// * Copying and iterating. +// * Set operations (union/intersect etc). +// +// TODO(dyaroshev): develop standalone benchmarks to find performance boundaries +// for different types of sets crbug.com/682215. +// +// If you do write a benchmark that significantly depends on using sets please +// share your results at: +// https://groups.google.com/a/chromium.org/forum/#!searchin/chromium-dev/vector$20based/chromium-dev/4uQMma9vj9w/HaQ-WvMOAwAJ +// +// Important usability aspects: +// * flat_set implements std::set interface from C++11 where possible. It +// also has reserve(), capacity() and shrink_to_fit() from std::vector. +// * iteration invalidation rules differ: +// - all cases of std::vector::iterator invalidation also apply. +// - we ask (for now) to assume that move operations invalidate iterators. +// TODO(dyaroshev): Research the possibility of using a small buffer +// optimization crbug.com/682240. +// * Constructor sorts elements in a non-stable manner (unlike std::set). So +// among equivalent (with respect to provided compare) elements passed to +// the constructor it is unspecified with one will end up in the set. +// However insert()/emplace() methods are stable with respect to already +// inserted elements - an element that is already in the set will not be +// replaced. +// * allocator support is not implemented. +// * insert(first, last) and insert(std::initializer_list) are not +// implemented (see Notes section). +// +// Notes: +// Current implementation is based on boost::containers::flat_set, +// eastl::vector_set and folly::sorted_vector. All of these implementations do +// insert(first, last) as insertion one by one (some implementations with hints +// and/or reserve). Boost documentation claims this algorithm to be O(n*log(n)) +// but it seems to be a quadratic algorithm. For now we do not implement this +// method. +// TODO(dyaroshev): research an algorithm for range insertion crbug.com/682249. + +template <class Key, class Compare = std::less<Key>> +// Meets the requirements of Container, AssociativeContainer, +// ReversibleContainer. +// Requires: Key is Movable, Compare is a StrictWeakOrdering on Key. +class flat_set { + private: + using underlying_type = std::vector<Key>; + + public: + // -------------------------------------------------------------------------- + // Types. + // + using key_type = Key; + using key_compare = Compare; + using value_type = Key; + using value_compare = Compare; + + using pointer = typename underlying_type::pointer; + using const_pointer = typename underlying_type::const_pointer; + using reference = typename underlying_type::reference; + using const_reference = typename underlying_type::const_reference; + using size_type = typename underlying_type::size_type; + using difference_type = typename underlying_type::difference_type; + using iterator = typename underlying_type::iterator; + using const_iterator = typename underlying_type::const_iterator; + using reverse_iterator = typename underlying_type::reverse_iterator; + using const_reverse_iterator = + typename underlying_type::const_reverse_iterator; + + // -------------------------------------------------------------------------- + // Lifetime. + // + // Constructors that take range guarantee O(N * log^2(N)) + O(N) complexity + // and take O(N * log(N)) + O(N) if extra memory is available (N is a range + // length). + // + // Assume that move constructors invalidate iterators and references. + + flat_set(); + explicit flat_set(const Compare& comp); + + template <class InputIterator> + flat_set(InputIterator first, + InputIterator last, + const Compare& comp = Compare()); + + flat_set(const flat_set&); + flat_set(flat_set&&); + + flat_set(std::initializer_list<value_type> ilist, + const Compare& comp = Compare()); + + ~flat_set(); + + // -------------------------------------------------------------------------- + // Assignments. + // + // Assume that move assignment invalidates iterators and references. + + flat_set& operator=(const flat_set&); + flat_set& operator=(flat_set&&); + flat_set& operator=(std::initializer_list<value_type> ilist); + + // -------------------------------------------------------------------------- + // Memory management. + // + // Beware that shrink_to_fit() simply forwards the request to the + // underlying_type and its implementation is free to optimize otherwise and + // leave capacity() to be greater that its size. + // + // reserve() and shrink_to_fit() invalidate iterators and references. + + void reserve(size_type new_capacity); + size_type capacity() const; + void shrink_to_fit(); + + // -------------------------------------------------------------------------- + // Size management. + // + // clear() leaves the capacity() of the flat_set unchanged. + + void clear(); + + size_type size() const; + size_type max_size() const; + bool empty() const; + + // -------------------------------------------------------------------------- + // Iterators. + + iterator begin(); + const_iterator begin() const; + const_iterator cbegin() const; + + iterator end(); + const_iterator end() const; + const_iterator cend() const; + + reverse_iterator rbegin(); + const_reverse_iterator rbegin() const; + const_reverse_iterator crbegin() const; + + reverse_iterator rend(); + const_reverse_iterator rend() const; + const_reverse_iterator crend() const; + + // -------------------------------------------------------------------------- + // Insert operations. + // + // Assume that every operation invalidates iterators and references. + // Insertion of one element can take O(size). See the Notes section in the + // class comments on why we do not currently implement range insertion. + // Capacity of flat_set grows in an implementation-defined manner. + + std::pair<iterator, bool> insert(const value_type& val); + std::pair<iterator, bool> insert(value_type&& val); + + iterator insert(const_iterator position_hint, const value_type& x); + iterator insert(const_iterator position_hint, value_type&& x); + + template <class... Args> + std::pair<iterator, bool> emplace(Args&&... args); + + template <class... Args> + iterator emplace_hint(const_iterator position_hint, Args&&... args); + + // -------------------------------------------------------------------------- + // Erase operations. + // + // Assume that every operation invalidates iterators and references. + // + // erase(position), erase(first, last) can take O(size). + // erase(key) may take O(size) + O(log(size)). + // + // Prefer the erase(std::remove(), end()) idiom for deleting multiple + // elements. + + iterator erase(const_iterator position); + iterator erase(const_iterator first, const_iterator last); + size_type erase(const key_type& key); + + // -------------------------------------------------------------------------- + // Comparators. + + key_compare key_comp() const; + value_compare value_comp() const; + + // -------------------------------------------------------------------------- + // Search operations. + // + // Search operations have O(log(size)) complexity. + + size_type count(const key_type& key) const; + + iterator find(const key_type& key); + const_iterator find(const key_type& key) const; + + std::pair<iterator, iterator> equal_range(const key_type& ket); + std::pair<const_iterator, const_iterator> equal_range( + const key_type& key) const; + + iterator lower_bound(const key_type& key); + const_iterator lower_bound(const key_type& key) const; + + iterator upper_bound(const key_type& key); + const_iterator upper_bound(const key_type& key) const; + + // -------------------------------------------------------------------------- + // General operations. + // + // Assume that swap invalidates iterators and references. + // + // As with std::set, equality and ordering operations for the whole flat_set + // are equivalent to using equal() and lexicographical_compare() on the key + // types, rather than using element-wise key_comp() as e.g. lower_bound() + // does. Implementation note: currently we use operator==() and operator<() on + // std::vector, because they have the same contract we need, so we use them + // directly for brevity and in case it is more optimal than calling equal() + // and lexicograhpical_compare(). If the underlying container type is changed, + // this code may need to be modified. + + void swap(flat_set& other); + + friend bool operator==(const flat_set& lhs, const flat_set& rhs) { + return lhs.impl_.body_ == rhs.impl_.body_; + } + + friend bool operator!=(const flat_set& lhs, const flat_set& rhs) { + return !(lhs == rhs); + } + + friend bool operator<(const flat_set& lhs, const flat_set& rhs) { + return lhs.impl_.body_ < rhs.impl_.body_; + } + + friend bool operator>(const flat_set& lhs, const flat_set& rhs) { + return rhs < lhs; + } + + friend bool operator>=(const flat_set& lhs, const flat_set& rhs) { + return !(lhs < rhs); + } + + friend bool operator<=(const flat_set& lhs, const flat_set& rhs) { + return !(lhs > rhs); + } + + friend void swap(flat_set& lhs, flat_set& rhs) { lhs.swap(rhs); } + + private: + const flat_set& as_const() { return *this; } + + iterator const_cast_it(const_iterator c_it) { + auto distance = std::distance(cbegin(), c_it); + return std::next(begin(), distance); + } + + void sort_and_unique() { + // std::set sorts elements preserving stability because it doesn't have any + // performance wins in not doing that. We do, so we use an unstable sort. + std::sort(begin(), end(), value_comp()); + erase(std::unique(begin(), end(), + [this](const value_type& lhs, const value_type& rhs) { + // lhs is already <= rhs due to sort, therefore + // !(lhs < rhs) <=> lhs == rhs. + return !value_comp()(lhs, rhs); + }), + end()); + } + + // To support comparators that may not be possible to default-construct, we + // have to store an instance of Compare. Using this to store all internal + // state of flat_set and using private inheritance to store compare lets us + // take advantage of an empty base class optimization to avoid extra space in + // the common case when Compare has no state. + struct Impl : private Compare { + Impl() = default; + + template <class Cmp, class... Body> + explicit Impl(Cmp&& compare_arg, Body&&... underlying_type_args) + : Compare(std::forward<Cmp>(compare_arg)), + body_(std::forward<Body>(underlying_type_args)...) {} + + Compare compare() const { return *this; } + + underlying_type body_; + } impl_; +}; + +// ---------------------------------------------------------------------------- +// Lifetime. + +template <class Key, class Compare> +flat_set<Key, Compare>::flat_set() = default; + +template <class Key, class Compare> +flat_set<Key, Compare>::flat_set(const Compare& comp) : impl_(comp) {} + +template <class Key, class Compare> +template <class InputIterator> +flat_set<Key, Compare>::flat_set(InputIterator first, + InputIterator last, + const Compare& comp) + : impl_(comp, first, last) { + sort_and_unique(); +} + +template <class Key, class Compare> +flat_set<Key, Compare>::flat_set(const flat_set&) = default; + +template <class Key, class Compare> +flat_set<Key, Compare>::flat_set(flat_set&&) = default; + +template <class Key, class Compare> +flat_set<Key, Compare>::flat_set(std::initializer_list<value_type> ilist, + const Compare& comp) + : flat_set(std::begin(ilist), std::end(ilist), comp) {} + +template <class Key, class Compare> +flat_set<Key, Compare>::~flat_set() = default; + +// ---------------------------------------------------------------------------- +// Assignments. + +template <class Key, class Compare> +auto flat_set<Key, Compare>::operator=(const flat_set&) -> flat_set& = default; + +template <class Key, class Compare> +auto flat_set<Key, Compare>::operator=(flat_set &&) -> flat_set& = default; + +template <class Key, class Compare> +auto flat_set<Key, Compare>::operator=(std::initializer_list<value_type> ilist) + -> flat_set& { + impl_.body_ = ilist; + sort_and_unique(); + return *this; +} + +// ---------------------------------------------------------------------------- +// Memory management. + +template <class Key, class Compare> +void flat_set<Key, Compare>::reserve(size_type new_capacity) { + impl_.body_.reserve(new_capacity); +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::capacity() const -> size_type { + return impl_.body_.capacity(); +} + +template <class Key, class Compare> +void flat_set<Key, Compare>::shrink_to_fit() { + impl_.body_.shrink_to_fit(); +} + +// ---------------------------------------------------------------------------- +// Size management. + +template <class Key, class Compare> +void flat_set<Key, Compare>::clear() { + impl_.body_.clear(); +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::size() const -> size_type { + return impl_.body_.size(); +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::max_size() const -> size_type { + return impl_.body_.max_size(); +} + +template <class Key, class Compare> +bool flat_set<Key, Compare>::empty() const { + return impl_.body_.empty(); +} + +// ---------------------------------------------------------------------------- +// Iterators. + +template <class Key, class Compare> +auto flat_set<Key, Compare>::begin() -> iterator { + return impl_.body_.begin(); +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::begin() const -> const_iterator { + return impl_.body_.begin(); +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::cbegin() const -> const_iterator { + return impl_.body_.cbegin(); +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::end() -> iterator { + return impl_.body_.end(); +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::end() const -> const_iterator { + return impl_.body_.end(); +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::cend() const -> const_iterator { + return impl_.body_.cend(); +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::rbegin() -> reverse_iterator { + return impl_.body_.rbegin(); +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::rbegin() const -> const_reverse_iterator { + return impl_.body_.rbegin(); +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::crbegin() const -> const_reverse_iterator { + return impl_.body_.crbegin(); +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::rend() -> reverse_iterator { + return impl_.body_.rend(); +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::rend() const -> const_reverse_iterator { + return impl_.body_.rend(); +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::crend() const -> const_reverse_iterator { + return impl_.body_.crend(); +} + +// ---------------------------------------------------------------------------- +// Insert operations. +// +// Currently we use position_hint the same way as eastl or boost: +// https://github.com/electronicarts/EASTL/blob/master/include/EASTL/vector_set.h#L493 +// +// We duplicate code between copy and move version so that we can avoid +// creating a temporary value. + +template <class Key, class Compare> +auto flat_set<Key, Compare>::insert(const value_type& val) + -> std::pair<iterator, bool> { + auto position = lower_bound(val); + + if (position == end() || value_comp()(val, *position)) + return {impl_.body_.insert(position, val), true}; + + return {position, false}; +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::insert(value_type&& val) + -> std::pair<iterator, bool> { + auto position = lower_bound(val); + + if (position == end() || value_comp()(val, *position)) + return {impl_.body_.insert(position, std::move(val)), true}; + + return {position, false}; +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::insert(const_iterator position_hint, + const value_type& val) -> iterator { + if (position_hint == end() || value_comp()(val, *position_hint)) { + if (position_hint == begin() || value_comp()(*(position_hint - 1), val)) + // We have to cast away const because of crbug.com/677044. + return impl_.body_.insert(const_cast_it(position_hint), val); + } + return insert(val).first; +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::insert(const_iterator position_hint, + value_type&& val) -> iterator { + if (position_hint == end() || value_comp()(val, *position_hint)) { + if (position_hint == begin() || value_comp()(*(position_hint - 1), val)) + // We have to cast away const because of crbug.com/677044. + return impl_.body_.insert(const_cast_it(position_hint), std::move(val)); + } + return insert(std::move(val)).first; +} + +template <class Key, class Compare> +template <class... Args> +auto flat_set<Key, Compare>::emplace(Args&&... args) + -> std::pair<iterator, bool> { + return insert(value_type(std::forward<Args>(args)...)); +} + +template <class Key, class Compare> +template <class... Args> +auto flat_set<Key, Compare>::emplace_hint(const_iterator position_hint, + Args&&... args) -> iterator { + return insert(position_hint, value_type(std::forward<Args>(args)...)); +} + +// ---------------------------------------------------------------------------- +// Erase operations. + +template <class Key, class Compare> +auto flat_set<Key, Compare>::erase(const_iterator position) -> iterator { + // We have to cast away const because of crbug.com/677044. + return impl_.body_.erase(const_cast_it(position)); +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::erase(const key_type& val) -> size_type { + auto eq_range = equal_range(val); + auto res = std::distance(eq_range.first, eq_range.second); + // We have to cast away const because of crbug.com/677044. + erase(const_cast_it(eq_range.first), const_cast_it(eq_range.second)); + return res; +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::erase(const_iterator first, const_iterator last) + -> iterator { + // We have to cast away const because of crbug.com/677044. + return impl_.body_.erase(const_cast_it(first), const_cast_it(last)); +} + +// ---------------------------------------------------------------------------- +// Comparators. + +template <class Key, class Compare> +auto flat_set<Key, Compare>::key_comp() const -> key_compare { + return impl_.compare(); +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::value_comp() const -> value_compare { + return impl_.compare(); +} + +// ---------------------------------------------------------------------------- +// Search operations. + +template <class Key, class Compare> +auto flat_set<Key, Compare>::count(const key_type& key) const -> size_type { + auto eq_range = equal_range(key); + return std::distance(eq_range.first, eq_range.second); +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::find(const key_type& key) -> iterator { + return const_cast_it(as_const().find(key)); +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::find(const key_type& key) const -> const_iterator { + auto eq_range = equal_range(key); + return (eq_range.first == eq_range.second) ? end() : eq_range.first; +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::equal_range(const key_type& key) + -> std::pair<iterator, iterator> { + auto res = as_const().equal_range(key); + return {const_cast_it(res.first), const_cast_it(res.second)}; +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::equal_range(const key_type& key) const + -> std::pair<const_iterator, const_iterator> { + auto lower = lower_bound(key); + + if (lower == end() || key_comp()(key, *lower)) + return {lower, lower}; + + return {lower, std::next(lower)}; +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::lower_bound(const key_type& key) -> iterator { + return const_cast_it(as_const().lower_bound(key)); +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::lower_bound(const key_type& key) const + -> const_iterator { + return std::lower_bound(begin(), end(), key, key_comp()); +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::upper_bound(const key_type& key) -> iterator { + return const_cast_it(as_const().upper_bound(key)); +} + +template <class Key, class Compare> +auto flat_set<Key, Compare>::upper_bound(const key_type& key) const + -> const_iterator { + return std::upper_bound(begin(), end(), key, key_comp()); +} + +// ---------------------------------------------------------------------------- +// General operations. + +template <class Key, class Compare> +void flat_set<Key, Compare>::swap(flat_set& other) { + std::swap(impl_, other.impl_); +} + +} // namespace base + +#endif // BASE_CONTAINERS_FLAT_SET_H_
diff --git a/base/containers/flat_set_unittest.cc b/base/containers/flat_set_unittest.cc new file mode 100644 index 0000000..1c7a46a --- /dev/null +++ b/base/containers/flat_set_unittest.cc
@@ -0,0 +1,1244 @@ +// 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/containers/flat_set.h" + +// Following tests are ported and extended tests from libcpp for std::set. +// They can be found here: +// https://github.com/llvm-mirror/libcxx/tree/master/test/std/containers/associative/set +// +// Not ported tests: +// * No tests with PrivateConstructor and std::less<> changed to std::less<T> +// These tests have to do with C++14 std::less<> +// http://en.cppreference.com/w/cpp/utility/functional/less_void +// and add support for templated versions of lookup functions. +// Current implementation of flat containers doesn't support it. +// * No tests with TemplateConstructor. +// Library working group issue: LWG #2059 +// http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2059 +// There is an ambiguity between erase with an iterator and erase with a key, +// if key has a templated constructor. We have to fix this. +// * No tests for max_size() +// Has to do with allocator support. +// * No tests with DefaultOnly. +// Standard containers allocate each element in the separate node on the heap +// and then manipulate these nodes. Flat containers store their elements in +// contiguous memory and move them around, type is required to be movable. +// * No tests for N3644. +// This proposal suggests that all default constructed iterators compare +// equal. Currently we use std::vector iterators and they don't implement +// this. +// * No tests with min_allocator and no tests counting allocations. +// Flat sets currently don't support allocators. +// * No tests for range insertion. Flat sets currently do not support this +// functionality. + +#include <string> +#include <vector> + +#include "base/macros.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +class MoveOnly { + public: + explicit MoveOnly(int data = 1) : data_(data) {} + MoveOnly(MoveOnly&& other) : data_(other.data_) { other.data_ = 0; } + MoveOnly& operator=(MoveOnly&& other) { + data_ = other.data_; + other.data_ = 0; + return *this; + } + + friend bool operator<(const MoveOnly& lhs, const MoveOnly& rhs) { + return lhs.data_ < rhs.data_; + } + + int data() const { return data_; } + + private: + int data_; + + DISALLOW_COPY_AND_ASSIGN(MoveOnly); +}; + +template <class It> +class InputIterator { + public: + using iterator_category = std::input_iterator_tag; + using value_type = typename std::iterator_traits<It>::value_type; + using difference_type = typename std::iterator_traits<It>::difference_type; + using pointer = It; + using reference = typename std::iterator_traits<It>::reference; + + InputIterator() : it_() {} + explicit InputIterator(It it) : it_(it) {} + + reference operator*() const { return *it_; } + pointer operator->() const { return it_; } + + InputIterator& operator++() { + ++it_; + return *this; + } + InputIterator operator++(int) { + InputIterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(const InputIterator& lhs, const InputIterator& rhs) { + return lhs.it_ == rhs.it_; + } + friend bool operator!=(const InputIterator& lhs, const InputIterator& rhs) { + return !(lhs == rhs); + } + + private: + It it_; +}; + +template <typename It> +InputIterator<It> MakeInputIterator(It it) { + return InputIterator<It>(it); +} + +class Emplaceable { + public: + Emplaceable() : Emplaceable(0, 0.0) {} + Emplaceable(int i, double d) : int_(i), double_(d) {} + Emplaceable(Emplaceable&& other) : int_(other.int_), double_(other.double_) { + other.int_ = 0; + other.double_ = 0.0; + } + + Emplaceable& operator=(Emplaceable&& other) { + int_ = other.int_; + other.int_ = 0; + double_ = other.double_; + other.double_ = 0.0; + return *this; + } + + friend bool operator==(const Emplaceable& lhs, const Emplaceable& rhs) { + return std::tie(lhs.int_, lhs.double_) == std::tie(rhs.int_, rhs.double_); + } + + friend bool operator<(const Emplaceable& lhs, const Emplaceable& rhs) { + return std::tie(lhs.int_, lhs.double_) < std::tie(rhs.int_, rhs.double_); + } + + private: + int int_; + double double_; + + DISALLOW_COPY_AND_ASSIGN(Emplaceable); +}; + +class NonDefaultConstructibleCompare { + public: + explicit NonDefaultConstructibleCompare(int) {} + + template <typename T> + bool operator()(const T& lhs, const T& rhs) { + return std::less<T>()(lhs, rhs); + } +}; + +// Common test sets. +using IntSet = base::flat_set<int>; +using MoveOnlySet = base::flat_set<MoveOnly>; +using EmplaceableSet = base::flat_set<Emplaceable>; +using ReversedSet = base::flat_set<int, std::greater<int>>; + +// TODO(dyaroshev): replace less<int> with less<>, once we have it +// crbug.com/682254. +using SetWithLess = base::flat_set<int, std::less<int>>; + +using SetWithStrangeCompare = + base::flat_set<int, NonDefaultConstructibleCompare>; + +using ::testing::ElementsAre; + +} // namespace + +// ---------------------------------------------------------------------------- +// Class. + +// Check that base::flat_set and its iterators can be instantiated with an +// incomplete type. + +TEST(FlatSet, IncompleteType) { + struct A { + using Set = base::flat_set<A>; + int data; + Set set_with_incomplete_type; + Set::iterator it; + Set::const_iterator cit; + + // We do not declare operator< because clang complains that it's unused. + }; + + A a; +} + +TEST(FlatSet, Stability) { + using Pair = std::pair<int, int>; + + struct LessByFirst { + bool operator()(const Pair& lhs, const Pair& rhs) { + return lhs.first < rhs.first; + } + }; + + using Set = base::flat_set<Pair, LessByFirst>; + + // Constructors are not stable. + Set cont{{0, 0}, {1, 0}, {0, 1}, {2, 0}, {0, 2}, {1, 1}}; + + auto NoneOfSecondsAreTwo = [&cont] { + return std::none_of(cont.begin(), cont.end(), + [](const Pair& elem) { return elem.second == 2; }); + }; + + // Should not replace existing. + cont.insert(Pair(0, 2)); + cont.insert(Pair(1, 2)); + cont.insert(Pair(2, 2)); + + EXPECT_TRUE(NoneOfSecondsAreTwo()) + << "insert should be stable with respect to constructor"; + + cont.insert(Pair(3, 0)); + cont.insert(Pair(3, 2)); + + EXPECT_TRUE(NoneOfSecondsAreTwo()) + << "insert should be stable with respect to previous insert"; +} + +// ---------------------------------------------------------------------------- +// Types. + +// key_type +// key_compare +// value_type +// value_compare +// pointer +// const_pointer +// reference +// const_reference +// size_type +// difference_type +// iterator +// const_iterator +// reverse_iterator +// const_reverse_iterator + +TEST(FlatSet, Types) { + // These are guaranteed to be portable. + static_assert((std::is_same<int, IntSet::key_type>::value), ""); + static_assert((std::is_same<int, IntSet::value_type>::value), ""); + static_assert((std::is_same<std::less<int>, IntSet::key_compare>::value), ""); + static_assert((std::is_same<std::less<int>, IntSet::value_compare>::value), + ""); + static_assert((std::is_same<int&, IntSet::reference>::value), ""); + static_assert((std::is_same<const int&, IntSet::const_reference>::value), ""); + static_assert((std::is_same<int*, IntSet::pointer>::value), ""); + static_assert((std::is_same<const int*, IntSet::const_pointer>::value), ""); +} + +// ---------------------------------------------------------------------------- +// Lifetime. + +// flat_set() +// flat_set(const Compare& comp) + +TEST(FlatSet, DefaultConstructor) { + { + IntSet cont; + EXPECT_THAT(cont, ElementsAre()); + } + + { + SetWithStrangeCompare cont(NonDefaultConstructibleCompare(0)); + EXPECT_THAT(cont, ElementsAre()); + } +} + +// flat_set(InputIterator first, +// InputIterator last, +// const Compare& comp = Compare()) + +TEST(FlatSet, RangeConstructor) { + { + IntSet::value_type input_vals[] = {1, 1, 1, 2, 2, 2, 3, 3, 3}; + + IntSet cont(MakeInputIterator(std::begin(input_vals)), + MakeInputIterator(std::end(input_vals))); + EXPECT_THAT(cont, ElementsAre(1, 2, 3)); + } + { + SetWithStrangeCompare::value_type input_vals[] = {1, 1, 1, 2, 2, + 2, 3, 3, 3}; + + SetWithStrangeCompare cont(MakeInputIterator(std::begin(input_vals)), + MakeInputIterator(std::end(input_vals)), + NonDefaultConstructibleCompare(0)); + EXPECT_THAT(cont, ElementsAre(1, 2, 3)); + } +} + +// flat_set(const flat_set& x) + +TEST(FlatSet, CopyConstructor) { + IntSet original{1, 2, 3, 4}; + IntSet copied(original); + + EXPECT_THAT(copied, ElementsAre(1, 2, 3, 4)); + + EXPECT_THAT(copied, ElementsAre(1, 2, 3, 4)); + EXPECT_THAT(original, ElementsAre(1, 2, 3, 4)); + EXPECT_EQ(original, copied); +} + +// flat_set(flat_set&& x) + +TEST(FlatSet, MoveConstructor) { + int input_range[] = {1, 2, 3, 4}; + + MoveOnlySet original(std::begin(input_range), std::end(input_range)); + MoveOnlySet moved(std::move(original)); + + EXPECT_EQ(1U, moved.count(MoveOnly(1))); + EXPECT_EQ(1U, moved.count(MoveOnly(2))); + EXPECT_EQ(1U, moved.count(MoveOnly(3))); + EXPECT_EQ(1U, moved.count(MoveOnly(4))); +} + +// flat_set(std::initializer_list<value_type> ilist, +// const Compare& comp = Compare()) + +TEST(FlatSet, InitializerListConstructor) { + { + IntSet cont{1, 2, 3, 4, 5, 6, 10, 8}; + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 8, 10)); + } + { + SetWithStrangeCompare cont({1, 2, 3, 4, 5, 6, 10, 8}, + NonDefaultConstructibleCompare(0)); + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 8, 10)); + } +} + +// ---------------------------------------------------------------------------- +// Assignments. + +// flat_set& operator=(const flat_set&) + +TEST(FlatSet, CopyAssignable) { + IntSet original{1, 2, 3, 4}; + IntSet copied; + copied = original; + + EXPECT_THAT(copied, ElementsAre(1, 2, 3, 4)); + EXPECT_THAT(original, ElementsAre(1, 2, 3, 4)); + EXPECT_EQ(original, copied); +} + +// flat_set& operator=(flat_set&&) + +TEST(FlatSet, MoveAssignable) { + int input_range[] = {1, 2, 3, 4}; + + MoveOnlySet original(std::begin(input_range), std::end(input_range)); + MoveOnlySet moved; + moved = std::move(original); + + EXPECT_EQ(1U, moved.count(MoveOnly(1))); + EXPECT_EQ(1U, moved.count(MoveOnly(2))); + EXPECT_EQ(1U, moved.count(MoveOnly(3))); + EXPECT_EQ(1U, moved.count(MoveOnly(4))); +} + +// flat_set& operator=(std::initializer_list<value_type> ilist) + +TEST(FlatSet, InitializerListAssignable) { + IntSet cont{0}; + cont = {1, 2, 3, 4, 5, 6, 10, 8}; + + EXPECT_EQ(0U, cont.count(0)); + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 8, 10)); +} + +// -------------------------------------------------------------------------- +// Memory management. + +// void reserve(size_type new_capacity) + +TEST(FlatSet, Reserve) { + IntSet cont{1, 2, 3}; + + cont.reserve(5); + EXPECT_LE(5U, cont.capacity()); +} + +// size_type capacity() const + +TEST(FlatSet, Capacity) { + IntSet cont{1, 2, 3}; + + EXPECT_LE(cont.size(), cont.capacity()); + cont.reserve(5); + EXPECT_LE(cont.size(), cont.capacity()); +} + +// void shrink_to_fit() + +TEST(FlatSet, ShrinkToFit) { + IntSet cont{1, 2, 3}; + + IntSet::size_type capacity_before = cont.capacity(); + cont.shrink_to_fit(); + EXPECT_GE(capacity_before, cont.capacity()); +} + +// ---------------------------------------------------------------------------- +// Size management. + +// void clear() + +TEST(FlatSet, Clear) { + IntSet cont{1, 2, 3, 4, 5, 6, 7, 8}; + cont.clear(); + EXPECT_THAT(cont, ElementsAre()); +} + +// size_type size() const + +TEST(FlatSet, Size) { + IntSet cont; + + EXPECT_EQ(0U, cont.size()); + cont.insert(2); + EXPECT_EQ(1U, cont.size()); + cont.insert(1); + EXPECT_EQ(2U, cont.size()); + cont.insert(3); + EXPECT_EQ(3U, cont.size()); + cont.erase(cont.begin()); + EXPECT_EQ(2U, cont.size()); + cont.erase(cont.begin()); + EXPECT_EQ(1U, cont.size()); + cont.erase(cont.begin()); + EXPECT_EQ(0U, cont.size()); +} + +// bool empty() const + +TEST(FlatSet, Empty) { + IntSet cont; + + EXPECT_TRUE(cont.empty()); + cont.insert(1); + EXPECT_FALSE(cont.empty()); + cont.clear(); + EXPECT_TRUE(cont.empty()); +} + +// ---------------------------------------------------------------------------- +// Iterators. + +// iterator begin() +// const_iterator begin() const +// iterator end() +// const_iterator end() const +// +// reverse_iterator rbegin() +// const_reverse_iterator rbegin() const +// reverse_iterator rend() +// const_reverse_iterator rend() const +// +// const_iterator cbegin() const +// const_iterator cend() const +// const_reverse_iterator crbegin() const +// const_reverse_iterator crend() const + +TEST(FlatSet, Iterators) { + IntSet cont{1, 2, 3, 4, 5, 6, 7, 8}; + + auto size = static_cast<IntSet::difference_type>(cont.size()); + + EXPECT_EQ(size, std::distance(cont.begin(), cont.end())); + EXPECT_EQ(size, std::distance(cont.cbegin(), cont.cend())); + EXPECT_EQ(size, std::distance(cont.rbegin(), cont.rend())); + EXPECT_EQ(size, std::distance(cont.crbegin(), cont.crend())); + + { + IntSet::iterator it = cont.begin(); + IntSet::const_iterator c_it = cont.cbegin(); + EXPECT_EQ(it, c_it); + for (int j = 1; it != cont.end(); ++it, ++c_it, ++j) { + EXPECT_EQ(j, *it); + EXPECT_EQ(j, *c_it); + } + } + { + IntSet::reverse_iterator rit = cont.rbegin(); + IntSet::const_reverse_iterator c_rit = cont.crbegin(); + EXPECT_EQ(rit, c_rit); + for (int j = static_cast<int>(size); rit != cont.rend(); + ++rit, ++c_rit, --j) { + EXPECT_EQ(j, *rit); + EXPECT_EQ(j, *c_rit); + } + } +} + +// ---------------------------------------------------------------------------- +// Insert operations. + +// pair<iterator, bool> insert(const value_type& val) + +TEST(FlatSet, InsertLValue) { + IntSet cont; + + int value = 2; + std::pair<IntSet::iterator, bool> result = cont.insert(value); + EXPECT_TRUE(result.second); + EXPECT_EQ(cont.begin(), result.first); + EXPECT_EQ(1U, cont.size()); + EXPECT_EQ(2, *result.first); + + value = 1; + result = cont.insert(value); + EXPECT_TRUE(result.second); + EXPECT_EQ(cont.begin(), result.first); + EXPECT_EQ(2U, cont.size()); + EXPECT_EQ(1, *result.first); + + value = 3; + result = cont.insert(value); + EXPECT_TRUE(result.second); + EXPECT_EQ(std::prev(cont.end()), result.first); + EXPECT_EQ(3U, cont.size()); + EXPECT_EQ(3, *result.first); + + value = 3; + result = cont.insert(value); + EXPECT_FALSE(result.second); + EXPECT_EQ(std::prev(cont.end()), result.first); + EXPECT_EQ(3U, cont.size()); + EXPECT_EQ(3, *result.first); +} + +// pair<iterator, bool> insert(value_type&& val) + +TEST(FlatSet, InsertRValue) { + MoveOnlySet cont; + + std::pair<MoveOnlySet::iterator, bool> result = cont.insert(MoveOnly(2)); + EXPECT_TRUE(result.second); + EXPECT_EQ(cont.begin(), result.first); + EXPECT_EQ(1U, cont.size()); + EXPECT_EQ(2, result.first->data()); + + result = cont.insert(MoveOnly(1)); + EXPECT_TRUE(result.second); + EXPECT_EQ(cont.begin(), result.first); + EXPECT_EQ(2U, cont.size()); + EXPECT_EQ(1, result.first->data()); + + result = cont.insert(MoveOnly(3)); + EXPECT_TRUE(result.second); + EXPECT_EQ(std::prev(cont.end()), result.first); + EXPECT_EQ(3U, cont.size()); + EXPECT_EQ(3, result.first->data()); + + result = cont.insert(MoveOnly(3)); + EXPECT_FALSE(result.second); + EXPECT_EQ(std::prev(cont.end()), result.first); + EXPECT_EQ(3U, cont.size()); + EXPECT_EQ(3, result.first->data()); +} + +// iterator insert(const_iterator position_hint, const value_type& val) + +TEST(FlatSet, InsertPositionLValue) { + IntSet cont; + + IntSet::iterator result = cont.insert(cont.cend(), 2); + EXPECT_EQ(cont.begin(), result); + EXPECT_EQ(1U, cont.size()); + EXPECT_EQ(2, *result); + + result = cont.insert(cont.cend(), 1); + EXPECT_EQ(cont.begin(), result); + EXPECT_EQ(2U, cont.size()); + EXPECT_EQ(1, *result); + + result = cont.insert(cont.cend(), 3); + EXPECT_EQ(std::prev(cont.end()), result); + EXPECT_EQ(3U, cont.size()); + EXPECT_EQ(3, *result); + + result = cont.insert(cont.cend(), 3); + EXPECT_EQ(std::prev(cont.end()), result); + EXPECT_EQ(3U, cont.size()); + EXPECT_EQ(3, *result); +} + +// iterator insert(const_iterator position_hint, value_type&& val) + +TEST(FlatSet, InsertPositionRValue) { + MoveOnlySet cont; + + MoveOnlySet::iterator result = cont.insert(cont.cend(), MoveOnly(2)); + EXPECT_EQ(cont.begin(), result); + EXPECT_EQ(1U, cont.size()); + EXPECT_EQ(2, result->data()); + + result = cont.insert(cont.cend(), MoveOnly(1)); + EXPECT_EQ(cont.begin(), result); + EXPECT_EQ(2U, cont.size()); + EXPECT_EQ(1, result->data()); + + result = cont.insert(cont.cend(), MoveOnly(3)); + EXPECT_EQ(std::prev(cont.end()), result); + EXPECT_EQ(3U, cont.size()); + EXPECT_EQ(3, result->data()); + + result = cont.insert(cont.cend(), MoveOnly(3)); + EXPECT_EQ(std::prev(cont.end()), result); + EXPECT_EQ(3U, cont.size()); + EXPECT_EQ(3, result->data()); +} + +// template <class... Args> +// pair<iterator, bool> emplace(Args&&... args) + +TEST(FlatSet, Emplace) { + { + EmplaceableSet cont; + + std::pair<EmplaceableSet::iterator, bool> result = cont.emplace(); + EXPECT_TRUE(result.second); + EXPECT_EQ(cont.begin(), result.first); + EXPECT_EQ(1U, cont.size()); + EXPECT_EQ(Emplaceable(), *cont.begin()); + + result = cont.emplace(2, 3.5); + EXPECT_TRUE(result.second); + EXPECT_EQ(std::next(cont.begin()), result.first); + EXPECT_EQ(2U, cont.size()); + EXPECT_EQ(Emplaceable(2, 3.5), *result.first); + + result = cont.emplace(2, 3.5); + EXPECT_FALSE(result.second); + EXPECT_EQ(std::next(cont.begin()), result.first); + EXPECT_EQ(2U, cont.size()); + EXPECT_EQ(Emplaceable(2, 3.5), *result.first); + } + { + IntSet cont; + + std::pair<IntSet::iterator, bool> result = cont.emplace(2); + EXPECT_TRUE(result.second); + EXPECT_EQ(cont.begin(), result.first); + EXPECT_EQ(1U, cont.size()); + EXPECT_EQ(2, *result.first); + } +} + +// template <class... Args> +// iterator emplace_hint(const_iterator position_hint, Args&&... args) + +TEST(FlatSet, EmplacePosition) { + { + EmplaceableSet cont; + + EmplaceableSet::iterator result = cont.emplace_hint(cont.cend()); + EXPECT_EQ(cont.begin(), result); + EXPECT_EQ(1U, cont.size()); + EXPECT_EQ(Emplaceable(), *cont.begin()); + + result = cont.emplace_hint(cont.cend(), 2, 3.5); + EXPECT_EQ(std::next(cont.begin()), result); + EXPECT_EQ(2U, cont.size()); + EXPECT_EQ(Emplaceable(2, 3.5), *result); + + result = cont.emplace_hint(cont.cbegin(), 2, 3.5); + EXPECT_EQ(std::next(cont.begin()), result); + EXPECT_EQ(2U, cont.size()); + EXPECT_EQ(Emplaceable(2, 3.5), *result); + } + { + IntSet cont; + + IntSet::iterator result = cont.emplace_hint(cont.cend(), 2); + EXPECT_EQ(cont.begin(), result); + EXPECT_EQ(1U, cont.size()); + EXPECT_EQ(2, *result); + } +} + +// ---------------------------------------------------------------------------- +// Erase operations. + +// iterator erase(const_iterator position_hint) + +TEST(FlatSet, ErasePosition) { + IntSet cont{1, 2, 3, 4, 5, 6, 7, 8}; + + IntSet::iterator it = cont.erase(std::next(cont.cbegin(), 3)); + EXPECT_EQ(std::next(cont.begin(), 3), it); + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 5, 6, 7, 8)); + + it = cont.erase(std::next(cont.cbegin(), 0)); + EXPECT_EQ(cont.begin(), it); + EXPECT_THAT(cont, ElementsAre(2, 3, 5, 6, 7, 8)); + + it = cont.erase(std::next(cont.cbegin(), 5)); + EXPECT_EQ(cont.end(), it); + EXPECT_THAT(cont, ElementsAre(2, 3, 5, 6, 7)); + + it = cont.erase(std::next(cont.cbegin(), 1)); + EXPECT_EQ(std::next(cont.begin()), it); + EXPECT_THAT(cont, ElementsAre(2, 5, 6, 7)); + + it = cont.erase(std::next(cont.cbegin(), 2)); + EXPECT_EQ(std::next(cont.begin(), 2), it); + EXPECT_THAT(cont, ElementsAre(2, 5, 7)); + + it = cont.erase(std::next(cont.cbegin(), 2)); + EXPECT_EQ(std::next(cont.begin(), 2), it); + EXPECT_THAT(cont, ElementsAre(2, 5)); + + it = cont.erase(std::next(cont.cbegin(), 0)); + EXPECT_EQ(std::next(cont.begin(), 0), it); + EXPECT_THAT(cont, ElementsAre(5)); + + it = cont.erase(cont.cbegin()); + EXPECT_EQ(cont.begin(), it); + EXPECT_EQ(cont.end(), it); +} + +// iterator erase(const_iterator first, const_iterator last) + +TEST(FlatSet, EraseRange) { + IntSet cont{1, 2, 3, 4, 5, 6, 7, 8}; + + IntSet::iterator it = + cont.erase(std::next(cont.cbegin(), 5), std::next(cont.cbegin(), 5)); + EXPECT_EQ(std::next(cont.begin(), 5), it); + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 7, 8)); + + it = cont.erase(std::next(cont.cbegin(), 3), std::next(cont.cbegin(), 4)); + EXPECT_EQ(std::next(cont.begin(), 3), it); + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 5, 6, 7, 8)); + + it = cont.erase(std::next(cont.cbegin(), 2), std::next(cont.cbegin(), 5)); + EXPECT_EQ(std::next(cont.begin(), 2), it); + EXPECT_THAT(cont, ElementsAre(1, 2, 7, 8)); + + it = cont.erase(std::next(cont.cbegin(), 0), std::next(cont.cbegin(), 2)); + EXPECT_EQ(std::next(cont.begin(), 0), it); + EXPECT_THAT(cont, ElementsAre(7, 8)); + + it = cont.erase(cont.cbegin(), cont.cend()); + EXPECT_EQ(cont.begin(), it); + EXPECT_EQ(cont.end(), it); +} + +// size_type erase(const key_type& key) + +TEST(FlatSet, EraseKey) { + IntSet cont{1, 2, 3, 4, 5, 6, 7, 8}; + + EXPECT_EQ(0U, cont.erase(9)); + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 7, 8)); + + EXPECT_EQ(1U, cont.erase(4)); + EXPECT_THAT(cont, ElementsAre(1, 2, 3, 5, 6, 7, 8)); + + EXPECT_EQ(1U, cont.erase(1)); + EXPECT_THAT(cont, ElementsAre(2, 3, 5, 6, 7, 8)); + + EXPECT_EQ(1U, cont.erase(8)); + EXPECT_THAT(cont, ElementsAre(2, 3, 5, 6, 7)); + + EXPECT_EQ(1U, cont.erase(3)); + EXPECT_THAT(cont, ElementsAre(2, 5, 6, 7)); + + EXPECT_EQ(1U, cont.erase(6)); + EXPECT_THAT(cont, ElementsAre(2, 5, 7)); + + EXPECT_EQ(1U, cont.erase(7)); + EXPECT_THAT(cont, ElementsAre(2, 5)); + + EXPECT_EQ(1U, cont.erase(2)); + EXPECT_THAT(cont, ElementsAre(5)); + + EXPECT_EQ(1U, cont.erase(5)); + EXPECT_THAT(cont, ElementsAre()); +} + +// ---------------------------------------------------------------------------- +// Comparators. + +// key_compare key_comp() const + +TEST(FlatSet, KeyComp) { + ReversedSet cont{1, 2, 3, 4, 5}; + + EXPECT_TRUE(std::is_sorted(cont.begin(), cont.end(), cont.key_comp())); + int new_elements[] = {6, 7, 8, 9, 10}; + std::copy(std::begin(new_elements), std::end(new_elements), + std::inserter(cont, cont.end())); + EXPECT_TRUE(std::is_sorted(cont.begin(), cont.end(), cont.key_comp())); +} + +// value_compare value_comp() const + +TEST(FlatSet, ValueComp) { + ReversedSet cont{1, 2, 3, 4, 5}; + + EXPECT_TRUE(std::is_sorted(cont.begin(), cont.end(), cont.value_comp())); + int new_elements[] = {6, 7, 8, 9, 10}; + std::copy(std::begin(new_elements), std::end(new_elements), + std::inserter(cont, cont.end())); + EXPECT_TRUE(std::is_sorted(cont.begin(), cont.end(), cont.value_comp())); +} + +// ---------------------------------------------------------------------------- +// Search operations. + +// size_type count(const key_type& key) const + +TEST(FlatSet, Count) { + { + const IntSet cont{5, 6, 7, 8, 9, 10, 11, 12}; + + EXPECT_EQ(1U, cont.count(5)); + EXPECT_EQ(1U, cont.count(6)); + EXPECT_EQ(1U, cont.count(7)); + EXPECT_EQ(1U, cont.count(8)); + EXPECT_EQ(1U, cont.count(9)); + EXPECT_EQ(1U, cont.count(10)); + EXPECT_EQ(1U, cont.count(11)); + EXPECT_EQ(1U, cont.count(12)); + EXPECT_EQ(0U, cont.count(4)); + } + { + const SetWithLess cont{5, 6, 7, 8, 9, 10, 11, 12}; + + EXPECT_EQ(1U, cont.count(5)); + EXPECT_EQ(1U, cont.count(6)); + EXPECT_EQ(1U, cont.count(7)); + EXPECT_EQ(1U, cont.count(8)); + EXPECT_EQ(1U, cont.count(9)); + EXPECT_EQ(1U, cont.count(10)); + EXPECT_EQ(1U, cont.count(11)); + EXPECT_EQ(1U, cont.count(12)); + EXPECT_EQ(0U, cont.count(4)); + } +} + +// iterator find(const key_type& key) +// const_iterator find(const key_type& key) const + +TEST(FlatSet, Find) { + { + IntSet cont{5, 6, 7, 8, 9, 10, 11, 12}; + + EXPECT_EQ(cont.begin(), cont.find(5)); + EXPECT_EQ(std::next(cont.begin()), cont.find(6)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.find(7)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.find(8)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.find(9)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.find(10)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.find(11)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.find(12)); + EXPECT_EQ(std::next(cont.begin(), 8), cont.find(4)); + } + { + const IntSet cont{5, 6, 7, 8, 9, 10, 11, 12}; + + EXPECT_EQ(cont.begin(), cont.find(5)); + EXPECT_EQ(std::next(cont.begin()), cont.find(6)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.find(7)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.find(8)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.find(9)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.find(10)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.find(11)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.find(12)); + EXPECT_EQ(std::next(cont.begin(), 8), cont.find(4)); + } + { + SetWithLess cont{5, 6, 7, 8, 9, 10, 11, 12}; + + EXPECT_EQ(cont.begin(), cont.find(5)); + EXPECT_EQ(std::next(cont.begin()), cont.find(6)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.find(7)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.find(8)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.find(9)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.find(10)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.find(11)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.find(12)); + EXPECT_EQ(std::next(cont.begin(), 8), cont.find(4)); + } +} + +// pair<iterator, iterator> equal_range(const key_type& key) +// pair<const_iterator, const_iterator> equal_range(const key_type& key) const + +TEST(FlatSet, EqualRange) { + { + IntSet cont{5, 7, 9, 11, 13, 15, 17, 19}; + + std::pair<IntSet::iterator, IntSet::iterator> result = cont.equal_range(5); + EXPECT_EQ(std::next(cont.begin(), 0), result.first); + EXPECT_EQ(std::next(cont.begin(), 1), result.second); + result = cont.equal_range(7); + EXPECT_EQ(std::next(cont.begin(), 1), result.first); + EXPECT_EQ(std::next(cont.begin(), 2), result.second); + result = cont.equal_range(9); + EXPECT_EQ(std::next(cont.begin(), 2), result.first); + EXPECT_EQ(std::next(cont.begin(), 3), result.second); + result = cont.equal_range(11); + EXPECT_EQ(std::next(cont.begin(), 3), result.first); + EXPECT_EQ(std::next(cont.begin(), 4), result.second); + result = cont.equal_range(13); + EXPECT_EQ(std::next(cont.begin(), 4), result.first); + EXPECT_EQ(std::next(cont.begin(), 5), result.second); + result = cont.equal_range(15); + EXPECT_EQ(std::next(cont.begin(), 5), result.first); + EXPECT_EQ(std::next(cont.begin(), 6), result.second); + result = cont.equal_range(17); + EXPECT_EQ(std::next(cont.begin(), 6), result.first); + EXPECT_EQ(std::next(cont.begin(), 7), result.second); + result = cont.equal_range(19); + EXPECT_EQ(std::next(cont.begin(), 7), result.first); + EXPECT_EQ(std::next(cont.begin(), 8), result.second); + result = cont.equal_range(4); + EXPECT_EQ(std::next(cont.begin(), 0), result.first); + EXPECT_EQ(std::next(cont.begin(), 0), result.second); + result = cont.equal_range(6); + EXPECT_EQ(std::next(cont.begin(), 1), result.first); + EXPECT_EQ(std::next(cont.begin(), 1), result.second); + result = cont.equal_range(8); + EXPECT_EQ(std::next(cont.begin(), 2), result.first); + EXPECT_EQ(std::next(cont.begin(), 2), result.second); + result = cont.equal_range(10); + EXPECT_EQ(std::next(cont.begin(), 3), result.first); + EXPECT_EQ(std::next(cont.begin(), 3), result.second); + result = cont.equal_range(12); + EXPECT_EQ(std::next(cont.begin(), 4), result.first); + EXPECT_EQ(std::next(cont.begin(), 4), result.second); + result = cont.equal_range(14); + EXPECT_EQ(std::next(cont.begin(), 5), result.first); + EXPECT_EQ(std::next(cont.begin(), 5), result.second); + result = cont.equal_range(16); + EXPECT_EQ(std::next(cont.begin(), 6), result.first); + EXPECT_EQ(std::next(cont.begin(), 6), result.second); + result = cont.equal_range(18); + EXPECT_EQ(std::next(cont.begin(), 7), result.first); + EXPECT_EQ(std::next(cont.begin(), 7), result.second); + result = cont.equal_range(20); + EXPECT_EQ(std::next(cont.begin(), 8), result.first); + EXPECT_EQ(std::next(cont.begin(), 8), result.second); + } + { + const IntSet cont{5, 7, 9, 11, 13, 15, 17, 19}; + + std::pair<IntSet::const_iterator, IntSet::const_iterator> result = + cont.equal_range(5); + EXPECT_EQ(std::next(cont.begin(), 0), result.first); + EXPECT_EQ(std::next(cont.begin(), 1), result.second); + result = cont.equal_range(7); + EXPECT_EQ(std::next(cont.begin(), 1), result.first); + EXPECT_EQ(std::next(cont.begin(), 2), result.second); + result = cont.equal_range(9); + EXPECT_EQ(std::next(cont.begin(), 2), result.first); + EXPECT_EQ(std::next(cont.begin(), 3), result.second); + result = cont.equal_range(11); + EXPECT_EQ(std::next(cont.begin(), 3), result.first); + EXPECT_EQ(std::next(cont.begin(), 4), result.second); + result = cont.equal_range(13); + EXPECT_EQ(std::next(cont.begin(), 4), result.first); + EXPECT_EQ(std::next(cont.begin(), 5), result.second); + result = cont.equal_range(15); + EXPECT_EQ(std::next(cont.begin(), 5), result.first); + EXPECT_EQ(std::next(cont.begin(), 6), result.second); + result = cont.equal_range(17); + EXPECT_EQ(std::next(cont.begin(), 6), result.first); + EXPECT_EQ(std::next(cont.begin(), 7), result.second); + result = cont.equal_range(19); + EXPECT_EQ(std::next(cont.begin(), 7), result.first); + EXPECT_EQ(std::next(cont.begin(), 8), result.second); + result = cont.equal_range(4); + EXPECT_EQ(std::next(cont.begin(), 0), result.first); + EXPECT_EQ(std::next(cont.begin(), 0), result.second); + result = cont.equal_range(6); + EXPECT_EQ(std::next(cont.begin(), 1), result.first); + EXPECT_EQ(std::next(cont.begin(), 1), result.second); + result = cont.equal_range(8); + EXPECT_EQ(std::next(cont.begin(), 2), result.first); + EXPECT_EQ(std::next(cont.begin(), 2), result.second); + result = cont.equal_range(10); + EXPECT_EQ(std::next(cont.begin(), 3), result.first); + EXPECT_EQ(std::next(cont.begin(), 3), result.second); + result = cont.equal_range(12); + EXPECT_EQ(std::next(cont.begin(), 4), result.first); + EXPECT_EQ(std::next(cont.begin(), 4), result.second); + result = cont.equal_range(14); + EXPECT_EQ(std::next(cont.begin(), 5), result.first); + EXPECT_EQ(std::next(cont.begin(), 5), result.second); + result = cont.equal_range(16); + EXPECT_EQ(std::next(cont.begin(), 6), result.first); + EXPECT_EQ(std::next(cont.begin(), 6), result.second); + result = cont.equal_range(18); + EXPECT_EQ(std::next(cont.begin(), 7), result.first); + EXPECT_EQ(std::next(cont.begin(), 7), result.second); + result = cont.equal_range(20); + EXPECT_EQ(std::next(cont.begin(), 8), result.first); + EXPECT_EQ(std::next(cont.begin(), 8), result.second); + } + { + SetWithLess cont{5, 7, 9, 11, 13, 15, 17, 19}; + + std::pair<SetWithLess::iterator, SetWithLess::iterator> result = + cont.equal_range(5); + EXPECT_EQ(std::next(cont.begin(), 0), result.first); + EXPECT_EQ(std::next(cont.begin(), 1), result.second); + result = cont.equal_range(7); + EXPECT_EQ(std::next(cont.begin(), 1), result.first); + EXPECT_EQ(std::next(cont.begin(), 2), result.second); + result = cont.equal_range(9); + EXPECT_EQ(std::next(cont.begin(), 2), result.first); + EXPECT_EQ(std::next(cont.begin(), 3), result.second); + result = cont.equal_range(11); + EXPECT_EQ(std::next(cont.begin(), 3), result.first); + EXPECT_EQ(std::next(cont.begin(), 4), result.second); + result = cont.equal_range(13); + EXPECT_EQ(std::next(cont.begin(), 4), result.first); + EXPECT_EQ(std::next(cont.begin(), 5), result.second); + result = cont.equal_range(15); + EXPECT_EQ(std::next(cont.begin(), 5), result.first); + EXPECT_EQ(std::next(cont.begin(), 6), result.second); + result = cont.equal_range(17); + EXPECT_EQ(std::next(cont.begin(), 6), result.first); + EXPECT_EQ(std::next(cont.begin(), 7), result.second); + result = cont.equal_range(19); + EXPECT_EQ(std::next(cont.begin(), 7), result.first); + EXPECT_EQ(std::next(cont.begin(), 8), result.second); + result = cont.equal_range(4); + EXPECT_EQ(std::next(cont.begin(), 0), result.first); + EXPECT_EQ(std::next(cont.begin(), 0), result.second); + result = cont.equal_range(6); + EXPECT_EQ(std::next(cont.begin(), 1), result.first); + EXPECT_EQ(std::next(cont.begin(), 1), result.second); + result = cont.equal_range(8); + EXPECT_EQ(std::next(cont.begin(), 2), result.first); + EXPECT_EQ(std::next(cont.begin(), 2), result.second); + result = cont.equal_range(10); + EXPECT_EQ(std::next(cont.begin(), 3), result.first); + EXPECT_EQ(std::next(cont.begin(), 3), result.second); + result = cont.equal_range(12); + EXPECT_EQ(std::next(cont.begin(), 4), result.first); + EXPECT_EQ(std::next(cont.begin(), 4), result.second); + result = cont.equal_range(14); + EXPECT_EQ(std::next(cont.begin(), 5), result.first); + EXPECT_EQ(std::next(cont.begin(), 5), result.second); + result = cont.equal_range(16); + EXPECT_EQ(std::next(cont.begin(), 6), result.first); + EXPECT_EQ(std::next(cont.begin(), 6), result.second); + result = cont.equal_range(18); + EXPECT_EQ(std::next(cont.begin(), 7), result.first); + EXPECT_EQ(std::next(cont.begin(), 7), result.second); + result = cont.equal_range(20); + EXPECT_EQ(std::next(cont.begin(), 8), result.first); + EXPECT_EQ(std::next(cont.begin(), 8), result.second); + } +} + +// iterator lower_bound(const key_type& key); +// const_iterator lower_bound(const key_type& key) const; + +TEST(FlatSet, LowerBound) { + { + IntSet cont{5, 7, 9, 11, 13, 15, 17, 19}; + + EXPECT_EQ(cont.begin(), cont.lower_bound(5)); + EXPECT_EQ(std::next(cont.begin()), cont.lower_bound(7)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.lower_bound(9)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.lower_bound(11)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.lower_bound(13)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.lower_bound(15)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.lower_bound(17)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.lower_bound(19)); + EXPECT_EQ(std::next(cont.begin(), 0), cont.lower_bound(4)); + EXPECT_EQ(std::next(cont.begin(), 1), cont.lower_bound(6)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.lower_bound(8)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.lower_bound(10)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.lower_bound(12)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.lower_bound(14)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.lower_bound(16)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.lower_bound(18)); + EXPECT_EQ(std::next(cont.begin(), 8), cont.lower_bound(20)); + } + { + const IntSet cont{5, 7, 9, 11, 13, 15, 17, 19}; + + EXPECT_EQ(cont.begin(), cont.lower_bound(5)); + EXPECT_EQ(std::next(cont.begin()), cont.lower_bound(7)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.lower_bound(9)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.lower_bound(11)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.lower_bound(13)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.lower_bound(15)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.lower_bound(17)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.lower_bound(19)); + EXPECT_EQ(std::next(cont.begin(), 0), cont.lower_bound(4)); + EXPECT_EQ(std::next(cont.begin(), 1), cont.lower_bound(6)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.lower_bound(8)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.lower_bound(10)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.lower_bound(12)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.lower_bound(14)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.lower_bound(16)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.lower_bound(18)); + EXPECT_EQ(std::next(cont.begin(), 8), cont.lower_bound(20)); + } + { + SetWithLess cont{5, 7, 9, 11, 13, 15, 17, 19}; + + EXPECT_EQ(cont.begin(), cont.lower_bound(5)); + EXPECT_EQ(std::next(cont.begin()), cont.lower_bound(7)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.lower_bound(9)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.lower_bound(11)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.lower_bound(13)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.lower_bound(15)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.lower_bound(17)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.lower_bound(19)); + EXPECT_EQ(std::next(cont.begin(), 0), cont.lower_bound(4)); + EXPECT_EQ(std::next(cont.begin(), 1), cont.lower_bound(6)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.lower_bound(8)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.lower_bound(10)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.lower_bound(12)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.lower_bound(14)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.lower_bound(16)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.lower_bound(18)); + EXPECT_EQ(std::next(cont.begin(), 8), cont.lower_bound(20)); + } +} + +// iterator upper_bound(const key_type& key) +// const_iterator upper_bound(const key_type& key) const + +TEST(FlatSet, UpperBound) { + { + IntSet cont{5, 7, 9, 11, 13, 15, 17, 19}; + + EXPECT_EQ(std::next(cont.begin(), 1), cont.upper_bound(5)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.upper_bound(7)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.upper_bound(9)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.upper_bound(11)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.upper_bound(13)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.upper_bound(15)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.upper_bound(17)); + EXPECT_EQ(std::next(cont.begin(), 8), cont.upper_bound(19)); + EXPECT_EQ(std::next(cont.begin(), 0), cont.upper_bound(4)); + EXPECT_EQ(std::next(cont.begin(), 1), cont.upper_bound(6)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.upper_bound(8)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.upper_bound(10)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.upper_bound(12)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.upper_bound(14)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.upper_bound(16)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.upper_bound(18)); + EXPECT_EQ(std::next(cont.begin(), 8), cont.upper_bound(20)); + } + { + const IntSet cont{5, 7, 9, 11, 13, 15, 17, 19}; + + EXPECT_EQ(std::next(cont.begin(), 1), cont.upper_bound(5)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.upper_bound(7)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.upper_bound(9)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.upper_bound(11)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.upper_bound(13)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.upper_bound(15)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.upper_bound(17)); + EXPECT_EQ(std::next(cont.begin(), 8), cont.upper_bound(19)); + EXPECT_EQ(std::next(cont.begin(), 0), cont.upper_bound(4)); + EXPECT_EQ(std::next(cont.begin(), 1), cont.upper_bound(6)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.upper_bound(8)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.upper_bound(10)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.upper_bound(12)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.upper_bound(14)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.upper_bound(16)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.upper_bound(18)); + EXPECT_EQ(std::next(cont.begin(), 8), cont.upper_bound(20)); + } + { + SetWithLess cont{5, 7, 9, 11, 13, 15, 17, 19}; + + EXPECT_EQ(std::next(cont.begin(), 1), cont.upper_bound(5)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.upper_bound(7)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.upper_bound(9)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.upper_bound(11)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.upper_bound(13)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.upper_bound(15)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.upper_bound(17)); + EXPECT_EQ(std::next(cont.begin(), 8), cont.upper_bound(19)); + EXPECT_EQ(std::next(cont.begin(), 0), cont.upper_bound(4)); + EXPECT_EQ(std::next(cont.begin(), 1), cont.upper_bound(6)); + EXPECT_EQ(std::next(cont.begin(), 2), cont.upper_bound(8)); + EXPECT_EQ(std::next(cont.begin(), 3), cont.upper_bound(10)); + EXPECT_EQ(std::next(cont.begin(), 4), cont.upper_bound(12)); + EXPECT_EQ(std::next(cont.begin(), 5), cont.upper_bound(14)); + EXPECT_EQ(std::next(cont.begin(), 6), cont.upper_bound(16)); + EXPECT_EQ(std::next(cont.begin(), 7), cont.upper_bound(18)); + EXPECT_EQ(std::next(cont.begin(), 8), cont.upper_bound(20)); + } +} + +// ---------------------------------------------------------------------------- +// General operations. + +// void swap(flat_set& other) +// void swap(flat_set& lhs, flat_set& rhs) + +TEST(FlatSetOurs, Swap) { + IntSet x{1, 2, 3}; + IntSet y{4}; + swap(x, y); + EXPECT_THAT(x, ElementsAre(4)); + EXPECT_THAT(y, ElementsAre(1, 2, 3)); + + y.swap(x); + EXPECT_THAT(x, ElementsAre(1, 2, 3)); + EXPECT_THAT(y, ElementsAre(4)); +} + +// bool operator==(const flat_set& lhs, const flat_set& rhs) +// bool operator!=(const flat_set& lhs, const flat_set& rhs) +// bool operator<(const flat_set& lhs, const flat_set& rhs) +// bool operator>(const flat_set& lhs, const flat_set& rhs) +// bool operator<=(const flat_set& lhs, const flat_set& rhs) +// bool operator>=(const flat_set& lhs, const flat_set& rhs) + +TEST(FlatSet, Comparison) { + // Provided comparator does not participate in comparison. + ReversedSet biggest{3}; + ReversedSet smallest{1}; + ReversedSet middle{1, 2}; + + EXPECT_EQ(biggest, biggest); + EXPECT_NE(biggest, smallest); + EXPECT_LT(smallest, middle); + EXPECT_LE(smallest, middle); + EXPECT_LE(middle, middle); + EXPECT_GT(biggest, middle); + EXPECT_GE(biggest, middle); + EXPECT_GE(biggest, biggest); +}
diff --git a/base/process/process.h b/base/process/process.h index 978ca78..fc2add2 100644 --- a/base/process/process.h +++ b/base/process/process.h
@@ -76,6 +76,9 @@ // Returns true if processes can be backgrounded. static bool CanBackgroundProcesses(); + // Terminates the current process immediately with |exit_code|. + static void TerminateCurrentProcessImmediately(int exit_code); + // Returns true if this objects represents a valid process. bool IsValid() const;
diff --git a/base/process/process_posix.cc b/base/process/process_posix.cc index 55b7ac90..9b94891d 100644 --- a/base/process/process_posix.cc +++ b/base/process/process_posix.cc
@@ -264,6 +264,11 @@ } #endif // !defined(OS_LINUX) && !defined(OS_MACOSX) +// static +void Process::TerminateCurrentProcessImmediately(int exit_code) { + _exit(exit_code); +} + bool Process::IsValid() const { return process_ != kNullProcessHandle; }
diff --git a/base/process/process_unittest.cc b/base/process/process_unittest.cc index 90bb95a..619d22b 100644 --- a/base/process/process_unittest.cc +++ b/base/process/process_unittest.cc
@@ -6,10 +6,12 @@ #include <utility> +#include "base/at_exit.h" #include "base/process/kill.h" #include "base/test/multiprocess_test.h" #include "base/test/test_timeouts.h" #include "base/threading/platform_thread.h" +#include "base/threading/thread_local.h" #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/multiprocess_func_list.h" @@ -148,6 +150,52 @@ #endif } +void AtExitHandler(void*) { + // At-exit handler should not be called at + // Process::TerminateCurrentProcessImmediately. + DCHECK(false); +} + +class ThreadLocalObject { + ~ThreadLocalObject() { + // Thread-local storage should not be destructed at + // Process::TerminateCurrentProcessImmediately. + DCHECK(false); + } +}; + +MULTIPROCESS_TEST_MAIN(TerminateCurrentProcessImmediatelyWithCode0) { + base::ThreadLocalPointer<ThreadLocalObject> object; + base::AtExitManager::RegisterCallback(&AtExitHandler, NULL); + Process::TerminateCurrentProcessImmediately(0); + NOTREACHED(); + return 42; +} + +TEST_F(ProcessTest, TerminateCurrentProcessImmediatelyWithZeroExitCode) { + Process process(SpawnChild("TerminateCurrentProcessImmediatelyWithCode0")); + ASSERT_TRUE(process.IsValid()); + int exit_code = 42; + ASSERT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(), + &exit_code)); + EXPECT_EQ(0, exit_code); +} + +MULTIPROCESS_TEST_MAIN(TerminateCurrentProcessImmediatelyWithCode250) { + Process::TerminateCurrentProcessImmediately(250); + NOTREACHED(); + return 42; +} + +TEST_F(ProcessTest, TerminateCurrentProcessImmediatelyWithNonZeroExitCode) { + Process process(SpawnChild("TerminateCurrentProcessImmediatelyWithCode250")); + ASSERT_TRUE(process.IsValid()); + int exit_code = 42; + ASSERT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(), + &exit_code)); + EXPECT_EQ(250, exit_code); +} + MULTIPROCESS_TEST_MAIN(FastSleepyChildProcess) { PlatformThread::Sleep(TestTimeouts::tiny_timeout() * 10); return 0;
diff --git a/base/process/process_win.cc b/base/process/process_win.cc index afc6a786..62321265 100644 --- a/base/process/process_win.cc +++ b/base/process/process_win.cc
@@ -82,6 +82,11 @@ return true; } +// static +void Process::TerminateCurrentProcessImmediately(int exit_code) { + ::TerminateProcess(GetCurrentProcess(), exit_code); +} + bool Process::IsValid() const { return process_.IsValid() || is_current(); }
diff --git a/base/task/cancelable_task_tracker.cc b/base/task/cancelable_task_tracker.cc index 92d82cc..2a68a57b 100644 --- a/base/task/cancelable_task_tracker.cc +++ b/base/task/cancelable_task_tracker.cc
@@ -74,8 +74,8 @@ CancelableTaskTracker::TaskId CancelableTaskTracker::PostTaskAndReply( TaskRunner* task_runner, const tracked_objects::Location& from_here, - const Closure& task, - const Closure& reply) { + Closure task, + Closure reply) { DCHECK(sequence_checker_.CalledOnValidSequence()); // We need a SequencedTaskRunnerHandle to run |reply|. @@ -87,15 +87,12 @@ TaskId id = next_id_; next_id_++; // int64_t is big enough that we ignore the potential overflow. - const Closure& untrack_closure = + Closure untrack_closure = Bind(&CancelableTaskTracker::Untrack, weak_factory_.GetWeakPtr(), id); - bool success = - task_runner->PostTaskAndReply(from_here, - Bind(&RunIfNotCanceled, flag, task), - Bind(&RunIfNotCanceledThenUntrack, - base::Owned(flag), - reply, - untrack_closure)); + bool success = task_runner->PostTaskAndReply( + from_here, Bind(&RunIfNotCanceled, flag, std::move(task)), + Bind(&RunIfNotCanceledThenUntrack, base::Owned(flag), std::move(reply), + std::move(untrack_closure))); if (!success) return kBadTaskId;
diff --git a/base/task/cancelable_task_tracker.h b/base/task/cancelable_task_tracker.h index 959c86f..4f64a24 100644 --- a/base/task/cancelable_task_tracker.h +++ b/base/task/cancelable_task_tracker.h
@@ -37,6 +37,8 @@ #include <stdint.h> +#include <utility> + #include "base/base_export.h" #include "base/bind.h" #include "base/callback.h" @@ -74,25 +76,21 @@ TaskId PostTaskAndReply(base::TaskRunner* task_runner, const tracked_objects::Location& from_here, - const base::Closure& task, - const base::Closure& reply); + base::Closure task, + base::Closure reply); template <typename TaskReturnType, typename ReplyArgType> - TaskId PostTaskAndReplyWithResult( - base::TaskRunner* task_runner, - const tracked_objects::Location& from_here, - const base::Callback<TaskReturnType(void)>& task, - const base::Callback<void(ReplyArgType)>& reply) { + TaskId PostTaskAndReplyWithResult(base::TaskRunner* task_runner, + const tracked_objects::Location& from_here, + base::Callback<TaskReturnType()> task, + base::Callback<void(ReplyArgType)> reply) { TaskReturnType* result = new TaskReturnType(); return PostTaskAndReply( - task_runner, - from_here, + task_runner, from_here, base::Bind(&base::internal::ReturnAsParamAdapter<TaskReturnType>, - task, - base::Unretained(result)), + std::move(task), base::Unretained(result)), base::Bind(&base::internal::ReplyAdapter<TaskReturnType, ReplyArgType>, - reply, - base::Owned(result))); + std::move(reply), base::Owned(result))); } // Creates a tracked TaskId and an associated IsCanceledCallback. Client can
diff --git a/base/task_runner.cc b/base/task_runner.cc index 262e1f8..35c0a23 100644 --- a/base/task_runner.cc +++ b/base/task_runner.cc
@@ -4,6 +4,8 @@ #include "base/task_runner.h" +#include <utility> + #include "base/compiler_specific.h" #include "base/logging.h" #include "base/threading/post_task_and_reply_impl.h" @@ -45,12 +47,11 @@ return PostDelayedTask(from_here, task, base::TimeDelta()); } -bool TaskRunner::PostTaskAndReply( - const tracked_objects::Location& from_here, - const Closure& task, - const Closure& reply) { +bool TaskRunner::PostTaskAndReply(const tracked_objects::Location& from_here, + Closure task, + Closure reply) { return PostTaskAndReplyTaskRunner(this).PostTaskAndReply( - from_here, task, reply); + from_here, std::move(task), std::move(reply)); } TaskRunner::TaskRunner() {}
diff --git a/base/task_runner.h b/base/task_runner.h index 9593835..be3039d 100644 --- a/base/task_runner.h +++ b/base/task_runner.h
@@ -8,7 +8,7 @@ #include <stddef.h> #include "base/base_export.h" -#include "base/callback_forward.h" +#include "base/callback.h" #include "base/location.h" #include "base/memory/ref_counted.h" #include "base/time/time.h" @@ -123,8 +123,8 @@ // and the reply will cancel itself safely because it is bound to a // WeakPtr<>. bool PostTaskAndReply(const tracked_objects::Location& from_here, - const Closure& task, - const Closure& reply); + Closure task, + Closure reply); protected: friend struct TaskRunnerTraits;
diff --git a/base/task_runner_util.h b/base/task_runner_util.h index e57d077..7fda076 100644 --- a/base/task_runner_util.h +++ b/base/task_runner_util.h
@@ -5,8 +5,11 @@ #ifndef BASE_TASK_RUNNER_UTIL_H_ #define BASE_TASK_RUNNER_UTIL_H_ +#include <utility> + #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/callback.h" #include "base/logging.h" #include "base/post_task_and_reply_with_result_internal.h" #include "base/task_runner.h" @@ -28,20 +31,18 @@ // Bind(&DoWorkAndReturn), // Bind(&Callback)); template <typename TaskReturnType, typename ReplyArgType> -bool PostTaskAndReplyWithResult( - TaskRunner* task_runner, - const tracked_objects::Location& from_here, - const Callback<TaskReturnType(void)>& task, - const Callback<void(ReplyArgType)>& reply) { +bool PostTaskAndReplyWithResult(TaskRunner* task_runner, + const tracked_objects::Location& from_here, + Callback<TaskReturnType()> task, + Callback<void(ReplyArgType)> reply) { DCHECK(task); DCHECK(reply); TaskReturnType* result = new TaskReturnType(); return task_runner->PostTaskAndReply( - from_here, - base::Bind(&internal::ReturnAsParamAdapter<TaskReturnType>, task, - result), - base::Bind(&internal::ReplyAdapter<TaskReturnType, ReplyArgType>, reply, - base::Owned(result))); + from_here, base::Bind(&internal::ReturnAsParamAdapter<TaskReturnType>, + std::move(task), result), + base::Bind(&internal::ReplyAdapter<TaskReturnType, ReplyArgType>, + std::move(reply), base::Owned(result))); } } // namespace base
diff --git a/base/task_scheduler/post_task.cc b/base/task_scheduler/post_task.cc index 8c3e941..3cf075d 100644 --- a/base/task_scheduler/post_task.cc +++ b/base/task_scheduler/post_task.cc
@@ -4,6 +4,8 @@ #include "base/task_scheduler/post_task.h" +#include <utility> + #include "base/task_scheduler/task_scheduler.h" #include "base/threading/post_task_and_reply_impl.h" @@ -40,9 +42,10 @@ } void PostTaskAndReply(const tracked_objects::Location& from_here, - const Closure& task, - const Closure& reply) { - PostTaskWithTraitsAndReply(from_here, TaskTraits(), task, reply); + Closure task, + Closure reply) { + PostTaskWithTraitsAndReply(from_here, TaskTraits(), std::move(task), + std::move(reply)); } void PostTaskWithTraits(const tracked_objects::Location& from_here, @@ -61,9 +64,10 @@ void PostTaskWithTraitsAndReply(const tracked_objects::Location& from_here, const TaskTraits& traits, - const Closure& task, - const Closure& reply) { - PostTaskAndReplyTaskRunner(traits).PostTaskAndReply(from_here, task, reply); + Closure task, + Closure reply) { + PostTaskAndReplyTaskRunner(traits).PostTaskAndReply( + from_here, std::move(task), std::move(reply)); } scoped_refptr<TaskRunner> CreateTaskRunnerWithTraits(const TaskTraits& traits) {
diff --git a/base/task_scheduler/post_task.h b/base/task_scheduler/post_task.h index 1c5c7096..163d06d 100644 --- a/base/task_scheduler/post_task.h +++ b/base/task_scheduler/post_task.h
@@ -5,9 +5,11 @@ #ifndef BASE_TASK_SCHEDULER_POST_TASK_H_ #define BASE_TASK_SCHEDULER_POST_TASK_H_ +#include <utility> + #include "base/base_export.h" #include "base/bind.h" -#include "base/callback_forward.h" +#include "base/callback.h" #include "base/location.h" #include "base/memory/ref_counted.h" #include "base/post_task_and_reply_with_result_internal.h" @@ -81,8 +83,8 @@ // PostTaskWithTraitsAndReply with plain TaskTraits. Can only be called when // SequencedTaskRunnerHandle::IsSet(). BASE_EXPORT void PostTaskAndReply(const tracked_objects::Location& from_here, - const Closure& task, - const Closure& reply); + Closure task, + Closure reply); // Posts |task| to the TaskScheduler and posts |reply| with the return value of // |task| as argument on the caller's execution context (i.e. same sequence or @@ -91,9 +93,10 @@ // TaskTraits. Can only be called when SequencedTaskRunnerHandle::IsSet(). template <typename TaskReturnType, typename ReplyArgType> void PostTaskAndReplyWithResult(const tracked_objects::Location& from_here, - const Callback<TaskReturnType(void)>& task, - const Callback<void(ReplyArgType)>& reply) { - PostTaskWithTraitsAndReplyWithResult(from_here, TaskTraits(), task, reply); + Callback<TaskReturnType(void)> task, + Callback<void(ReplyArgType)> reply) { + PostTaskWithTraitsAndReplyWithResult(from_here, TaskTraits(), std::move(task), + std::move(reply)); } // Posts |task| with specific |traits| to the TaskScheduler. @@ -119,8 +122,8 @@ BASE_EXPORT void PostTaskWithTraitsAndReply( const tracked_objects::Location& from_here, const TaskTraits& traits, - const Closure& task, - const Closure& reply); + Closure task, + Closure reply); // Posts |task| with specific |traits| to the TaskScheduler and posts |reply| // with the return value of |task| as argument on the caller's execution context @@ -130,14 +133,14 @@ void PostTaskWithTraitsAndReplyWithResult( const tracked_objects::Location& from_here, const TaskTraits& traits, - const Callback<TaskReturnType(void)>& task, - const Callback<void(ReplyArgType)>& reply) { + Callback<TaskReturnType()> task, + Callback<void(ReplyArgType)> reply) { TaskReturnType* result = new TaskReturnType(); return PostTaskWithTraitsAndReply( - from_here, traits, - Bind(&internal::ReturnAsParamAdapter<TaskReturnType>, task, result), - Bind(&internal::ReplyAdapter<TaskReturnType, ReplyArgType>, reply, - Owned(result))); + from_here, traits, Bind(&internal::ReturnAsParamAdapter<TaskReturnType>, + std::move(task), result), + Bind(&internal::ReplyAdapter<TaskReturnType, ReplyArgType>, + std::move(reply), Owned(result))); } // Returns a TaskRunner whose PostTask invocations result in scheduling tasks
diff --git a/base/threading/post_task_and_reply_impl.cc b/base/threading/post_task_and_reply_impl.cc index 7899f65..d16f8bd2 100644 --- a/base/threading/post_task_and_reply_impl.cc +++ b/base/threading/post_task_and_reply_impl.cc
@@ -4,8 +4,9 @@ #include "base/threading/post_task_and_reply_impl.h" +#include <utility> + #include "base/bind.h" -#include "base/callback.h" #include "base/debug/leak_annotations.h" #include "base/logging.h" #include "base/memory/ref_counted.h" @@ -28,13 +29,13 @@ class PostTaskAndReplyRelay { public: PostTaskAndReplyRelay(const tracked_objects::Location& from_here, - const Closure& task, - const Closure& reply) + Closure task, + Closure reply) : sequence_checker_(), from_here_(from_here), origin_task_runner_(SequencedTaskRunnerHandle::Get()), - reply_(reply), - task_(task) {} + reply_(std::move(reply)), + task_(std::move(task)) {} ~PostTaskAndReplyRelay() { DCHECK(sequence_checker_.CalledOnValidSequence()); @@ -77,12 +78,12 @@ bool PostTaskAndReplyImpl::PostTaskAndReply( const tracked_objects::Location& from_here, - const Closure& task, - const Closure& reply) { + Closure task, + Closure reply) { DCHECK(!task.is_null()) << from_here.ToString(); DCHECK(!reply.is_null()) << from_here.ToString(); PostTaskAndReplyRelay* relay = - new PostTaskAndReplyRelay(from_here, task, reply); + new PostTaskAndReplyRelay(from_here, std::move(task), std::move(reply)); // PostTaskAndReplyRelay self-destructs after executing |reply|. On the flip // side though, it is intentionally leaked if the |task| doesn't complete // before the origin sequence stops executing tasks. Annotate |relay| as leaky
diff --git a/base/threading/post_task_and_reply_impl.h b/base/threading/post_task_and_reply_impl.h index d058227..696b668 100644 --- a/base/threading/post_task_and_reply_impl.h +++ b/base/threading/post_task_and_reply_impl.h
@@ -9,7 +9,7 @@ #define BASE_THREADING_POST_TASK_AND_REPLY_IMPL_H_ #include "base/base_export.h" -#include "base/callback_forward.h" +#include "base/callback.h" #include "base/location.h" namespace base { @@ -29,8 +29,8 @@ // SequencedTaskRunnerHandle::IsSet(). Both |task| and |reply| are guaranteed // to be deleted on the sequence or thread that called this. bool PostTaskAndReply(const tracked_objects::Location& from_here, - const Closure& task, - const Closure& reply); + Closure task, + Closure reply); private: virtual bool PostTask(const tracked_objects::Location& from_here,
diff --git a/base/threading/worker_pool.cc b/base/threading/worker_pool.cc index 96a39148..9d2b3ba 100644 --- a/base/threading/worker_pool.cc +++ b/base/threading/worker_pool.cc
@@ -4,6 +4,8 @@ #include "base/threading/worker_pool.h" +#include <utility> + #include "base/bind.h" #include "base/compiler_specific.h" #include "base/debug/leak_annotations.h" @@ -100,8 +102,8 @@ } // namespace bool WorkerPool::PostTaskAndReply(const tracked_objects::Location& from_here, - const Closure& task, - const Closure& reply, + Closure task, + Closure reply, bool task_is_slow) { // Do not report PostTaskAndReplyRelay leaks in tests. There's nothing we can // do about them because WorkerPool doesn't have a flushing API. @@ -109,8 +111,8 @@ // http://crbug.com/290897 // Note: this annotation does not cover tasks posted through a TaskRunner. ANNOTATE_SCOPED_MEMORY_LEAK; - return PostTaskAndReplyWorkerPool(task_is_slow).PostTaskAndReply( - from_here, task, reply); + return PostTaskAndReplyWorkerPool(task_is_slow) + .PostTaskAndReply(from_here, std::move(task), std::move(reply)); } // static
diff --git a/base/threading/worker_pool.h b/base/threading/worker_pool.h index 1f1b818..865948e 100644 --- a/base/threading/worker_pool.h +++ b/base/threading/worker_pool.h
@@ -6,7 +6,7 @@ #define BASE_THREADING_WORKER_POOL_H_ #include "base/base_export.h" -#include "base/callback_forward.h" +#include "base/callback.h" #include "base/memory/ref_counted.h" namespace tracked_objects { @@ -38,8 +38,8 @@ // for |task| is a worker thread and you can specify |task_is_slow| just // like you can for PostTask above. static bool PostTaskAndReply(const tracked_objects::Location& from_here, - const Closure& task, - const Closure& reply, + Closure task, + Closure reply, bool task_is_slow); // Return true if the current thread is one that this WorkerPool runs tasks
diff --git a/build/android/pylib/results/presentation/javascript/main_html.js b/build/android/pylib/results/presentation/javascript/main_html.js new file mode 100644 index 0000000..2106fcd --- /dev/null +++ b/build/android/pylib/results/presentation/javascript/main_html.js
@@ -0,0 +1,186 @@ +// 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. + +function getArguments() { + // Returns the URL arguments as a dictionary. + args = {} + var s = location.search; + if (s) { + var vals = s.substring(1).split('&'); + for (var i = 0; i < vals.length; i++) { + var pair = vals[i].split('='); + args[pair[0]] = pair[1]; + } + } + return args; +} + +function showSuiteTable(show_the_table) { + document.getElementById('suite-table').style.display = ( + show_the_table ? 'table' : 'none'); +} + +function showTestTable(show_the_table) { + document.getElementById('test-table').style.display = ( + show_the_table ? 'table' : 'none'); +} + +function showTestsOfOneSuiteOnly(suite_name) { + setTitle('Test Results of Suite: ' + suite_name) + show_all = (suite_name == 'TOTAL') + var testTableBlocks = document.getElementById('test-table') + .getElementsByClassName('row_block'); + Array.prototype.slice.call(testTableBlocks) + .forEach(function(testTableBlock) { + if (!show_all) { + var table_block_in_suite = (testTableBlock.firstElementChild + .firstElementChild.firstElementChild.innerHTML) + .startsWith(suite_name); + if (!table_block_in_suite) { + testTableBlock.style.display = 'none'; + return; + } + } + testTableBlock.style.display = 'table-row-group'; + }); + showTestTable(true); + showSuiteTable(false); +} + +function showSuiteTableOnly() { + setTitle('Suites Summary') + showTestTable(false); + showSuiteTable(true); +} + +function setTitle(title) { + document.getElementById('summary-header').textContent = title; +} + +function sortByColumn(head) { + var table = head.parentNode.parentNode.parentNode; + var rowBlocks = Array.prototype.slice.call( + table.getElementsByTagName('tbody')); + + // Determine whether to asc or desc and set arrows. + var headers = head.parentNode.getElementsByTagName('th'); + var headIndex = Array.prototype.slice.call(headers).indexOf(head); + var asc = 1; + for (var i = 0; i < headers.length; i++) { + if (headers[i].dataset.ascSorted != 0) { + if (headers[i].dataset.ascSorted == 1) { + headers[i].getElementsByClassName('up')[0] + .style.display = 'none'; + } else { + headers[i].getElementsByClassName('down')[0] + .style.display = 'none'; + } + if (headers[i] == head) { + asc = headers[i].dataset.ascSorted * -1; + } else { + headers[i].dataset.ascSorted = 0; + } + break; + } + } + headers[headIndex].dataset.ascSorted = asc; + if (asc == 1) { + headers[headIndex].getElementsByClassName('up')[0] + .style.display = 'inline'; + } else { + headers[headIndex].getElementsByClassName('down')[0] + .style.display = 'inline'; + } + + // Sort the array by the specified column number (col) and order (asc). + rowBlocks.sort(function (a, b) { + if (a.style.display == 'none') { + return -1; + } else if (b.style.display == 'none') { + return 1; + } + var a_rows = Array.prototype.slice.call(a.children); + var b_rows = Array.prototype.slice.call(b.children); + if (head.className == "text") { + // If sorting by text, we only compare the entry on the first row. + var aInnerHTML = a_rows[0].children[headIndex].innerHTML; + var bInnerHTML = b_rows[0].children[headIndex].innerHTML; + return (aInnerHTML == bInnerHTML) ? 0 : ( + (aInnerHTML > bInnerHTML) ? asc : -1 * asc); + } else if (head.className == "number") { + // If sorting by number, for example, duration, + // we will sum up the durations of different test runs + // for one specific test case and sort by the sum. + var avalue = 0; + var bvalue = 0; + a_rows.forEach(function (row, i) { + var index = (i > 0) ? headIndex - 1 : headIndex; + avalue += Number(row.children[index].innerHTML); + }); + b_rows.forEach(function (row, i) { + var index = (i > 0) ? headIndex - 1 : headIndex; + bvalue += Number(row.children[index].innerHTML); + }); + } else if (head.className == "flaky") { + // Flakiness = (#total - #success - #skipped) / (#total - #skipped) + var a_success_or_skipped = 0; + var a_skipped = 0; + var b_success_or_skipped = 0; + var b_skipped = 0; + a_rows.forEach(function (row, i) { + var index = (i > 0) ? headIndex - 1 : headIndex; + var status = row.children[index].innerHTML.trim(); + if (status == 'SUCCESS') { + a_success_or_skipped += 1; + } + if (status == 'SKIPPED') { + a_success_or_skipped += 1; + a_skipped += 1; + } + }); + b_rows.forEach(function (row, i) { + var index = (i > 0) ? headIndex - 1 : headIndex; + var status = row.children[index].innerHTML.trim(); + if (status == 'SUCCESS') { + b_success_or_skipped += 1; + } + if (status == 'SKIPPED') { + b_success_or_skipped += 1; + b_skipped += 1; + } + }); + var atotal_minus_skipped = a_rows.length - a_skipped; + var btotal_minus_skipped = b_rows.length - b_skipped; + + var avalue = ((atotal_minus_skipped == 0) ? -1 : + (a_rows.length - a_success_or_skipped) / atotal_minus_skipped); + var bvalue = ((btotal_minus_skipped == 0) ? -1 : + (b_rows.length - b_success_or_skipped) / btotal_minus_skipped); + } + return asc * (avalue - bvalue); + }); + + for (var i = 0; i < rowBlocks.length; i++) { + table.appendChild(rowBlocks[i]); + } +} + +function loadPage() { + var args = getArguments(); + if ('suite' in args) { + // The user wants to visit detailed 'subpage' of that suite. + showTestsOfOneSuiteOnly(args['suite']); + } else { + // The user wants to visit the summary of all suites. + showSuiteTableOnly(); + } +} + +function reportIssues() { + var url = 'https://bugs.chromium.org/p/chromium/issues/entry?' + + 'labels=Pri-2,Type-Bug&summary=Result Details Feedback:&' + + 'comment=Please check out: ' + window.location; + var newWindow = window.open(url, '_blank'); + newWindow.focus(); +} \ No newline at end of file
diff --git a/build/android/pylib/results/presentation/template/main.html b/build/android/pylib/results/presentation/template/main.html new file mode 100644 index 0000000..cd8c103 --- /dev/null +++ b/build/android/pylib/results/presentation/template/main.html
@@ -0,0 +1,65 @@ +<!DOCTYPE html> +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <link rel="stylesheet" href="../../../../../../../default.css" type="text/css"> + <style> + table, th, td { + border: 1px solid black; + border-collapse: collapse; + } + th, td { + padding: 5px; + } + th { + cursor: pointer; + } + table { + width: 100%; + } + .center { + text-align: center; + } + .left { + text-align: left; + } + a { + text-decoration: none; + } + a:hover { + text-decoration: underline; + cursor: pointer; + } + .row_block:hover { + background-color: #F6F6F6; + } + .skipped, .success, .failure { + border-color: #000000; + } + </style> + <script type="text/javascript"> + {% include "javascript/main_html.js" %} + </script> + </head> + <body class="interface"> + <div class="content"> + <h2 id="summary-header"></h2> + {% for tb_value in tb_values %} + {% include 'template/table.html' %} + {% endfor %} + </div> + </br> + <a onclick="reportIssues();"><b>Feedback</b></a> + </body> + <script> + loadPage(); + // Enable sorting for each column of tables. + Array.prototype.slice.call(document.getElementsByTagName('th')) + .forEach(function(head) { + head.addEventListener( + "click", + function() { sortByColumn(head); }); + } + ); + </script> +</html> \ No newline at end of file
diff --git a/build/android/pylib/results/presentation/template/table.html b/build/android/pylib/results/presentation/template/table.html new file mode 100644 index 0000000..3ed498e --- /dev/null +++ b/build/android/pylib/results/presentation/template/table.html
@@ -0,0 +1,53 @@ +<table id="{{tb_value.table_id}}" class="info" style="display:none;"> + <thead class="heads"> + <tr> + {% for cell in tb_value.table_headers -%} + <th class="{{cell.class}}" data-asc-sorted=0> + {{cell.data}} + <span class="up" style="display:none;"> ↑</span> + <span class="down" style="display:none;"> ↓</span> + </th> + {%- endfor %} + </tr> + </thead> + {% for block in tb_value.table_row_blocks -%} + <tbody class="row_block"> + {% for row in block -%} + <tr class="{{tb_value.table_id}}-body-row"> + {% for cell in row -%} + {% if cell.rowspan -%} + <td rowspan="{{cell.rowspan}}" class="{{tb_value.table_id}}-body-column-{{loop.index0}} {{cell.class}}"> + {%- else -%} + <td rowspan="1" class="{{tb_value.table_id}}-body-column-{{loop.index0}} {{cell.class}}"> + {%- endif %} + {% if cell.cell_type == 'pre' -%} + <pre>{{cell.data}}</pre> + {%- elif cell.cell_type == 'links' -%} + {% for link in cell.links %} + <a href="{{link.href}}" target="{{link.target}}">{{link.data}}</a> + {% endfor %} + {%- else -%} + {{cell.data}} + {%- endif %} + </td> + {%- endfor %} + </tr> + {%- endfor %} + </tbody> + {%- endfor %} + <tfoot> + <tr> + {% for cell in tb_value.table_footer -%} + <td class="{{tb_value.table_id}}-summary-column-{{loop.index0}} {{cell.class}}"> + {% if cell.cell_type == 'links' -%} + {% for link in cell.links %} + <a href="{{link.href}}" target="{{link.target}}"><b>{{link.data}}</b></a> + {% endfor %} + {%- else -%} + <b>{{cell.data}}</b> + {%- endif %} + </td> + {%- endfor %} + </tr> + </tfoot> +</table>
diff --git a/build/android/pylib/results/presentation/test_results_presentation.py b/build/android/pylib/results/presentation/test_results_presentation.py new file mode 100755 index 0000000..3323727 --- /dev/null +++ b/build/android/pylib/results/presentation/test_results_presentation.py
@@ -0,0 +1,296 @@ +#! /usr/bin/env python +# +# 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. + +import argparse +import collections +import json +import os +import sys + +CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) +BASE_DIR = os.path.abspath(os.path.join( + CURRENT_DIR, '..', '..', '..', '..', '..')) +sys.path.append(os.path.join(BASE_DIR, 'third_party', 'markupsafe')) +sys.path.append(os.path.join(BASE_DIR, 'third_party', 'jinja2')) +import jinja2 +JINJA_ENVIRONMENT = jinja2.Environment( + loader=jinja2.FileSystemLoader(os.path.dirname(__file__)), + autoescape=True) + + +def cell(data, html_class='center'): + """Formats table cell data for processing in jinja template.""" + return { + 'data': data, + 'class': html_class, + } + + +def pre_cell(data, html_class='center'): + """Formats table <pre> cell data for processing in jinja template.""" + return { + 'cell_type': 'pre', + 'data': data, + 'class': html_class, + } + + +class LinkTarget(object): + # Opens the linked document in a new window or tab. + NEW_TAB = '_blank' + # Opens the linked document in the same frame as it was clicked. + CURRENT_TAB = '_self' + + +def link(data, href, target=LinkTarget.CURRENT_TAB): + """Formats <a> tag data for processing in jinja template. + + Args: + data: String link appears as on HTML page. + href: URL where link goes. + target: Where link should be opened (e.g. current tab or new tab). + """ + return { + 'data': data, + 'href': href, + 'target': target, + } + + +def links_cell(links, html_class='center', rowspan=None): + """Formats table cell with links for processing in jinja template. + + Args: + links: List of link dictionaries. Use |link| function to generate them. + html_class: Class for table cell. + rowspan: Rowspan HTML attribute. + """ + return { + 'cell_type': 'links', + 'class': html_class, + 'links': links, + 'rowspan': rowspan, + } + + +def logs_cell(result): + """Formats result logs data for processing in jinja template.""" + link_list = [] + for name, href in result.get('links', {}).iteritems(): + link_list.append(link( + data=name, + href=href, + target=LinkTarget.NEW_TAB)) + + if link_list: + return links_cell(link_list) + else: + return cell('(no logs)') + + +def code_search(test, cs_base_url): + """Returns URL for test on codesearch.""" + search = test.replace('#', '.') + return '%s/?q=%s&type=cs' % (cs_base_url, search) + + +def status_class(status): + """Returns HTML class for test status.""" + status = status.lower() + if status not in ('success', 'skipped'): + return 'failure %s' % status + return status + + +def create_test_table(results_dict, cs_base_url): + """Format test data for injecting into HTML table.""" + + header_row = [ + cell(data='test_name', html_class='text'), + cell(data='status', html_class='flaky'), + cell(data='elapsed_time_ms', html_class='number'), + cell(data='logs', html_class='text'), + cell(data='output_snippet', html_class='text'), + ] + + test_row_blocks = [] + for test_name, test_results in results_dict.iteritems(): + test_runs = [] + for index, result in enumerate(test_results): + if index == 0: + test_run = [links_cell( + links=[ + link(href=code_search(test_name, cs_base_url), + target=LinkTarget.NEW_TAB, + data=test_name)], + rowspan=len(test_results), + html_class='left %s' % test_name + )] # test_name + else: + test_run = [] + + test_run.extend([ + cell(data=result['status'], # status + html_class=('center %s' % + status_class(result['status']))), + cell(data=result['elapsed_time_ms']), # elapsed_time_ms + logs_cell(result), # logs + pre_cell(data=result['output_snippet'], # output_snippet + html_class='left'), + ]) + test_runs.append(test_run) + test_row_blocks.append(test_runs) + return header_row, test_row_blocks + + +def create_suite_table(results_dict): + """Format test suite data for injecting into HTML table.""" + + SUCCESS_COUNT_INDEX = 1 + FAIL_COUNT_INDEX = 2 + ALL_COUNT_INDEX = 3 + TIME_INDEX = 4 + + header_row = [ + cell(data='suite_name', html_class='text'), + cell(data='number_success_tests', html_class='number'), + cell(data='number_fail_tests', html_class='number'), + cell(data='all_tests', html_class='number'), + cell(data='elapsed_time_ms', html_class='number'), + ] + + footer_row = [ + links_cell( + links=[ + link(href=('?suite=%s' % 'TOTAL'), + target=LinkTarget.CURRENT_TAB, + data='TOTAL') + ], + ), # suite_name + cell(data=0), # number_success_tests + cell(data=0), # number_fail_tests + cell(data=0), # all_tests + cell(data=0), # elapsed_time_ms + ] + + suite_row_dict = {} + for test_name, test_results in results_dict.iteritems(): + # TODO(mikecase): This logic doesn't work if there are multiple test runs. + # That is, if 'per_iteration_data' has multiple entries. + # Since we only care about the result of the last test run. + result = test_results[-1] + + suite_name = (test_name.split('#')[0] if '#' in test_name + else test_name.split('.')[0]) + if suite_name in suite_row_dict: + suite_row = suite_row_dict[suite_name] + else: + suite_row = [ + links_cell( + links=[ + link(href=('?suite=%s' % suite_name), + target=LinkTarget.CURRENT_TAB, + data=suite_name)], + html_class='left' + ), # suite_name + cell(data=0), # number_success_tests + cell(data=0), # number_fail_tests + cell(data=0), # all_tests + cell(data=0), # elapsed_time_ms + ] + + suite_row_dict[suite_name] = suite_row + + suite_row[ALL_COUNT_INDEX]['data'] += 1 + footer_row[ALL_COUNT_INDEX]['data'] += 1 + + if result['status'] == 'SUCCESS': + suite_row[SUCCESS_COUNT_INDEX]['data'] += 1 + footer_row[SUCCESS_COUNT_INDEX]['data'] += 1 + elif result['status'] != 'SKIPPED': + suite_row[FAIL_COUNT_INDEX]['data'] += 1 + footer_row[FAIL_COUNT_INDEX]['data'] += 1 + + suite_row[TIME_INDEX]['data'] += result['elapsed_time_ms'] + footer_row[TIME_INDEX]['data'] += result['elapsed_time_ms'] + + for suite in suite_row_dict.values(): + if suite[FAIL_COUNT_INDEX]['data'] > 0: + suite[FAIL_COUNT_INDEX]['class'] += ' failure' + else: + suite[FAIL_COUNT_INDEX]['class'] += ' success' + + if footer_row[FAIL_COUNT_INDEX]['data'] > 0: + footer_row[FAIL_COUNT_INDEX]['class'] += ' failure' + else: + footer_row[FAIL_COUNT_INDEX]['class'] += ' success' + + return (header_row, + [[suite_row] for suite_row in suite_row_dict.values()], + footer_row) + + +def results_to_html(results_dict, cs_base_url, master_name): + """Convert list of test results into html format.""" + + test_rows_header, test_rows = create_test_table(results_dict, cs_base_url) + suite_rows_header, suite_rows, suite_row_footer = create_suite_table( + results_dict) + + suite_table_values = { + 'table_id': 'suite-table', + 'table_headers': suite_rows_header, + 'table_row_blocks': suite_rows, + 'table_footer': suite_row_footer, + } + + test_table_values = { + 'table_id': 'test-table', + 'table_headers': test_rows_header, + 'table_row_blocks': test_rows, + } + + main_template = JINJA_ENVIRONMENT.get_template( + os.path.join('template', 'main.html')) + return main_template.render( # pylint: disable=no-member + {'tb_values': [suite_table_values, test_table_values], + 'master_name': master_name}) + + +def result_details(json_path, cs_base_url, master_name): + """Get result details from json path and then convert results to html.""" + + with open(json_path) as json_file: + json_object = json.loads(json_file.read()) + + if not 'per_iteration_data' in json_object: + return 'Error: json file missing per_iteration_data.' + + results_dict = collections.defaultdict(list) + for testsuite_run in json_object['per_iteration_data']: + for test, test_runs in testsuite_run.iteritems(): + results_dict[test].extend(test_runs) + return results_to_html(results_dict, cs_base_url, master_name) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--json-file', help='Path of json file.', required=True) + parser.add_argument('--cs-base-url', help='Base url for code search.', + default='http://cs.chromium.org') + parser.add_argument('--master-name', help='Master name in urls.') + + args = parser.parse_args() + if os.path.exists(args.json_file): + result_html_string = result_details(args.json_file, args.cs_base_url, + args.master_name) + print result_html_string.encode('UTF-8') + else: + raise IOError('--json-file %s not found.' % args.json_file) + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/build/args/bots/chromium.fyi/headless_linux_dbg.gn b/build/args/bots/chromium.fyi/headless_linux_dbg.gn deleted file mode 100644 index a5f5a64..0000000 --- a/build/args/bots/chromium.fyi/headless_linux_dbg.gn +++ /dev/null
@@ -1,3 +0,0 @@ -import("//build/args/headless.gn") -is_debug = true -use_goma = true
diff --git a/build/args/bots/tryserver.chromium.linux/linux_chromium_headless_dbg.gn b/build/args/bots/tryserver.chromium.linux/linux_chromium_headless_dbg.gn deleted file mode 100644 index 70f8ffd..0000000 --- a/build/args/bots/tryserver.chromium.linux/linux_chromium_headless_dbg.gn +++ /dev/null
@@ -1,6 +0,0 @@ -import("//build/args/headless.gn") - -# TODO(perezju): Remove this config after recipe is moved to release trybot. -is_debug = true -use_goma = true -symbol_level = 1
diff --git a/build/args/bots/tryserver.chromium.linux/linux_chromium_headless_rel.gn b/build/args/bots/tryserver.chromium.linux/linux_chromium_headless_rel.gn deleted file mode 100644 index eeeec7c..0000000 --- a/build/args/bots/tryserver.chromium.linux/linux_chromium_headless_rel.gn +++ /dev/null
@@ -1,5 +0,0 @@ -import("//build/args/headless.gn") -is_debug = false -dcheck_always_on = true -use_goma = true -symbol_level = 1
diff --git a/build/package_mac_toolchain.py b/build/package_mac_toolchain.py index edce057..49eec87 100755 --- a/build/package_mac_toolchain.py +++ b/build/package_mac_toolchain.py
@@ -46,7 +46,7 @@ MAC_EXCLUDE_FOLDERS = [ 'Contents/Developer/Platforms/iPhoneOS.platform', -'Contents/Developer/Platforms/iPhoneSimulator.platform', +'Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs', ] IOS_EXCLUDE_FOLDERS = [
diff --git a/cc/OWNERS b/cc/OWNERS index e47a9eaa..cbba2c2b 100644 --- a/cc/OWNERS +++ b/cc/OWNERS
@@ -26,7 +26,6 @@ # scheduling / begin frames brianderson@chromium.org skyostil@chromium.org -mithro@mithis.com sunnyps@chromium.org # texture uploading @@ -56,7 +55,11 @@ # we miss you # jamesr@chromium.org # nduca@chromium.org +# mithro@mithis.com / tansell@chromium.org per-file *.isolate=maruel@chromium.org per-file *.isolate=tandrii@chromium.org per-file *.isolate=vadimsh@chromium.org + +# TEAM: graphics-dev@chromium.org +# COMPONENT: Internals>Compositing
diff --git a/cc/animation/OWNERS b/cc/animation/OWNERS index ed0b8de..4cd8d66b 100644 --- a/cc/animation/OWNERS +++ b/cc/animation/OWNERS
@@ -1 +1,4 @@ loyso@chromium.org + +# TEAM: style-dev@chromium.org +# COMPONENT: Internals>Compositing>Animation
diff --git a/cc/blink/OWNERS b/cc/blink/OWNERS new file mode 100644 index 0000000..bcf87b10 --- /dev/null +++ b/cc/blink/OWNERS
@@ -0,0 +1 @@ +# COMPONENT: Blink>Compositing
diff --git a/cc/blink/web_display_item_list_impl.cc b/cc/blink/web_display_item_list_impl.cc index 06e7d5e..52a5a05 100644 --- a/cc/blink/web_display_item_list_impl.cc +++ b/cc/blink/web_display_item_list_impl.cc
@@ -41,9 +41,9 @@ void WebDisplayItemListImpl::appendDrawingItem( const blink::WebRect& visual_rect, - sk_sp<const cc::PaintRecord> picture) { + sk_sp<const cc::PaintRecord> record) { display_item_list_->CreateAndAppendDrawingItem<cc::DrawingDisplayItem>( - visual_rect, std::move(picture)); + visual_rect, std::move(record)); } void WebDisplayItemListImpl::appendClipItem(
diff --git a/cc/blink/web_display_item_list_impl.h b/cc/blink/web_display_item_list_impl.h index fa723eba..ad1e95cc 100644 --- a/cc/blink/web_display_item_list_impl.h +++ b/cc/blink/web_display_item_list_impl.h
@@ -41,7 +41,7 @@ // blink::WebDisplayItemList implementation. void appendDrawingItem(const blink::WebRect& visual_rect, - sk_sp<const cc::PaintRecord> picture) override; + sk_sp<const cc::PaintRecord> record) override; void appendClipItem( const blink::WebRect& clip_rect, const blink::WebVector<SkRRect>& rounded_clip_rects) override;
diff --git a/cc/debug/rasterize_and_record_benchmark_impl.cc b/cc/debug/rasterize_and_record_benchmark_impl.cc index 9e3a9a7..044992c 100644 --- a/cc/debug/rasterize_and_record_benchmark_impl.cc +++ b/cc/debug/rasterize_and_record_benchmark_impl.cc
@@ -207,7 +207,7 @@ const RasterSource* layer_raster_source = layer->GetRasterSource(); rasterize_results_.total_memory_usage += - layer_raster_source->GetPictureMemoryUsage(); + layer_raster_source->GetMemoryUsage(); } RasterizeAndRecordBenchmarkImpl::RasterizeResults::RasterizeResults()
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc index 5a4a4c9d..3446f38 100644 --- a/cc/layers/layer.cc +++ b/cc/layers/layer.cc
@@ -217,7 +217,7 @@ return !layer_tree_host_->in_paint_layer_contents(); } -sk_sp<PaintRecord> Layer::GetPicture() const { +sk_sp<SkPicture> Layer::GetPicture() const { return nullptr; }
diff --git a/cc/layers/layer.h b/cc/layers/layer.h index 99bb550..d4d3ae9d 100644 --- a/cc/layers/layer.h +++ b/cc/layers/layer.h
@@ -328,8 +328,7 @@ virtual ScrollbarLayerInterface* ToScrollbarLayer(); - // TODO(enne): rename this to PaintRecord - virtual sk_sp<PaintRecord> GetPicture() const; + virtual sk_sp<SkPicture> GetPicture() const; // Constructs a LayerImpl of the correct runtime type for this Layer type. virtual std::unique_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl);
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc index 08c5761..ca425af 100644 --- a/cc/layers/picture_layer.cc +++ b/cc/layers/picture_layer.cc
@@ -141,10 +141,10 @@ is_mask_ = is_mask; } -sk_sp<PaintRecord> PictureLayer::GetPicture() const { - // We could either flatten the RecordingSource into a single - // PaintRecord, or paint a fresh one depending on what we intend to do with - // the record. For now we just paint a fresh one to get consistent results. +sk_sp<SkPicture> PictureLayer::GetPicture() const { + // We could either flatten the RecordingSource into a single SkPicture, or + // paint a fresh one depending on what we intend to do with it. For now we + // just paint a fresh one to get consistent results. if (!DrawsContent()) return nullptr;
diff --git a/cc/layers/picture_layer.h b/cc/layers/picture_layer.h index 21c7178..f4e2751 100644 --- a/cc/layers/picture_layer.h +++ b/cc/layers/picture_layer.h
@@ -35,7 +35,7 @@ void SetNeedsDisplayRect(const gfx::Rect& layer_rect) override; bool Update() override; void SetIsMask(bool is_mask) override; - sk_sp<PaintRecord> GetPicture() const override; + sk_sp<SkPicture> GetPicture() const override; bool IsSuitableForGpuRasterization() const override;
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc index 5f0c5f8..18609745 100644 --- a/cc/output/gl_renderer.cc +++ b/cc/output/gl_renderer.cc
@@ -2285,7 +2285,6 @@ gl_->Uniform1f(program->lut_size_location(), lut.size); gl_->ActiveTexture(GL_TEXTURE0); } - DCHECK_NE(program->yuv_and_resource_matrix_location(), -1); float yuv_to_rgb_matrix[16] = {0}; ComputeYUVToRGBMatrices(quad->color_space, quad->bits_per_channel, quad->resource_multiplier, quad->resource_offset,
diff --git a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc index d50b010..63f55e4 100644 --- a/cc/output/renderer_pixeltest.cc +++ b/cc/output/renderer_pixeltest.cc
@@ -950,17 +950,17 @@ this->quad_rect_.width() / 2, this->quad_rect_.height() / 2); - PaintFlags black_paint; - black_paint.setColor(SK_ColorBLACK); - PaintFlags blue_paint; - blue_paint.setColor(SK_ColorBLUE); - PaintFlags green_paint; - green_paint.setColor(SK_ColorGREEN); + PaintFlags black_flags; + black_flags.setColor(SK_ColorBLACK); + PaintFlags blue_flags; + blue_flags.setColor(SK_ColorBLUE); + PaintFlags green_flags; + green_flags.setColor(SK_ColorGREEN); std::unique_ptr<FakeRecordingSource> blue_recording = FakeRecordingSource::CreateFilledRecordingSource(this->quad_rect_.size()); - blue_recording->add_draw_rect_with_paint(outer_rect, black_paint); - blue_recording->add_draw_rect_with_paint(inner_rect, blue_paint); + blue_recording->add_draw_rect_with_flags(outer_rect, black_flags); + blue_recording->add_draw_rect_with_flags(inner_rect, blue_flags); blue_recording->Rerecord(); scoped_refptr<FakeRasterSource> blue_raster_source = FakeRasterSource::CreateFromRecordingSource(blue_recording.get(), false); @@ -975,8 +975,8 @@ std::unique_ptr<FakeRecordingSource> green_recording = FakeRecordingSource::CreateFilledRecordingSource(this->quad_rect_.size()); - green_recording->add_draw_rect_with_paint(outer_rect, green_paint); - green_recording->add_draw_rect_with_paint(inner_rect, black_paint); + green_recording->add_draw_rect_with_flags(outer_rect, green_flags); + green_recording->add_draw_rect_with_flags(inner_rect, black_flags); green_recording->Rerecord(); scoped_refptr<FakeRasterSource> green_raster_source = FakeRasterSource::CreateFromRecordingSource(green_recording.get(), false); @@ -1915,17 +1915,17 @@ bitmap.allocPixels( SkImageInfo::MakeN32Premul(mask_rect.width(), mask_rect.height())); PaintCanvas canvas(bitmap); - PaintFlags paint; - paint.setStyle(PaintFlags::kStroke_Style); - paint.setStrokeWidth(SkIntToScalar(4)); - paint.setColor(SK_ColorWHITE); + PaintFlags flags; + flags.setStyle(PaintFlags::kStroke_Style); + flags.setStrokeWidth(SkIntToScalar(4)); + flags.setColor(SK_ColorWHITE); canvas.clear(SK_ColorTRANSPARENT); gfx::Rect rect = mask_rect; while (!rect.IsEmpty()) { rect.Inset(6, 6, 4, 4); canvas.drawRect( SkRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height()), - paint); + flags); rect.Inset(6, 6, 4, 4); } @@ -2008,17 +2008,17 @@ bitmap.allocPixels( SkImageInfo::MakeN32Premul(mask_rect.width(), mask_rect.height())); PaintCanvas canvas(bitmap); - PaintFlags paint; - paint.setStyle(PaintFlags::kStroke_Style); - paint.setStrokeWidth(SkIntToScalar(4)); - paint.setColor(SK_ColorWHITE); + PaintFlags flags; + flags.setStyle(PaintFlags::kStroke_Style); + flags.setStrokeWidth(SkIntToScalar(4)); + flags.setColor(SK_ColorWHITE); canvas.clear(SK_ColorTRANSPARENT); gfx::Rect rect = mask_rect; while (!rect.IsEmpty()) { rect.Inset(6, 6, 4, 4); canvas.drawRect( SkRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height()), - paint); + flags); rect.Inset(6, 6, 4, 4); } @@ -2500,12 +2500,12 @@ std::unique_ptr<FakeRecordingSource> blue_recording = FakeRecordingSource::CreateFilledRecordingSource(blue_rect.size()); - PaintFlags red_paint; - red_paint.setColor(SK_ColorRED); - blue_recording->add_draw_rect_with_paint(blue_rect, red_paint); - PaintFlags blue_paint; - blue_paint.setColor(SK_ColorBLUE); - blue_recording->add_draw_rect_with_paint(blue_clip_rect, blue_paint); + PaintFlags red_flags; + red_flags.setColor(SK_ColorRED); + blue_recording->add_draw_rect_with_flags(blue_rect, red_flags); + PaintFlags blue_flags; + blue_flags.setColor(SK_ColorBLUE); + blue_recording->add_draw_rect_with_flags(blue_clip_rect, blue_flags); blue_recording->Rerecord(); scoped_refptr<FakeRasterSource> blue_raster_source = @@ -2531,9 +2531,9 @@ // One viewport-filling green quad. std::unique_ptr<FakeRecordingSource> green_recording = FakeRecordingSource::CreateFilledRecordingSource(viewport.size()); - PaintFlags green_paint; - green_paint.setColor(SK_ColorGREEN); - green_recording->add_draw_rect_with_paint(viewport, green_paint); + PaintFlags green_flags; + green_flags.setColor(SK_ColorGREEN); + green_recording->add_draw_rect_with_flags(viewport, green_flags); green_recording->Rerecord(); scoped_refptr<FakeRasterSource> green_raster_source = FakeRasterSource::CreateFromRecordingSource(green_recording.get(), false); @@ -2572,9 +2572,9 @@ // One viewport-filling 0.5-opacity green quad. std::unique_ptr<FakeRecordingSource> green_recording = FakeRecordingSource::CreateFilledRecordingSource(viewport.size()); - PaintFlags green_paint; - green_paint.setColor(SK_ColorGREEN); - green_recording->add_draw_rect_with_paint(viewport, green_paint); + PaintFlags green_flags; + green_flags.setColor(SK_ColorGREEN); + green_recording->add_draw_rect_with_flags(viewport, green_flags); green_recording->Rerecord(); scoped_refptr<FakeRasterSource> green_raster_source = FakeRasterSource::CreateFromRecordingSource(green_recording.get(), false); @@ -2593,9 +2593,9 @@ // One viewport-filling white quad. std::unique_ptr<FakeRecordingSource> white_recording = FakeRecordingSource::CreateFilledRecordingSource(viewport.size()); - PaintFlags white_paint; - white_paint.setColor(SK_ColorWHITE); - white_recording->add_draw_rect_with_paint(viewport, white_paint); + PaintFlags white_flags; + white_flags.setColor(SK_ColorWHITE); + white_recording->add_draw_rect_with_flags(viewport, white_flags); white_recording->Rerecord(); scoped_refptr<FakeRasterSource> white_raster_source = FakeRasterSource::CreateFromRecordingSource(white_recording.get(), false); @@ -2661,10 +2661,10 @@ std::unique_ptr<FakeRecordingSource> recording = FakeRecordingSource::CreateFilledRecordingSource(viewport.size()); - PaintFlags paint; - paint.setFilterQuality(kLow_SkFilterQuality); - recording->add_draw_image_with_paint(surface->makeImageSnapshot(), - gfx::Point(), paint); + PaintFlags flags; + flags.setFilterQuality(kLow_SkFilterQuality); + recording->add_draw_image_with_flags(surface->makeImageSnapshot(), + gfx::Point(), flags); recording->Rerecord(); scoped_refptr<FakeRasterSource> raster_source = FakeRasterSource::CreateFromRecordingSource(recording.get(), false); @@ -2710,10 +2710,10 @@ std::unique_ptr<FakeRecordingSource> recording = FakeRecordingSource::CreateFilledRecordingSource(viewport.size()); - PaintFlags paint; - paint.setFilterQuality(kLow_SkFilterQuality); - recording->add_draw_image_with_paint(surface->makeImageSnapshot(), - gfx::Point(), paint); + PaintFlags flags; + flags.setFilterQuality(kLow_SkFilterQuality); + recording->add_draw_image_with_flags(surface->makeImageSnapshot(), + gfx::Point(), flags); recording->Rerecord(); scoped_refptr<FakeRasterSource> raster_source = FakeRasterSource::CreateFromRecordingSource(recording.get(), false); @@ -2915,13 +2915,13 @@ std::unique_ptr<FakeRecordingSource> green_recording = FakeRecordingSource::CreateFilledRecordingSource(viewport.size()); - PaintFlags red_paint; - red_paint.setColor(SK_ColorRED); - green_recording->add_draw_rect_with_paint(viewport, red_paint); - PaintFlags green_paint; - green_paint.setColor(SK_ColorGREEN); - green_recording->add_draw_rect_with_paint(green_rect1, green_paint); - green_recording->add_draw_rect_with_paint(green_rect2, green_paint); + PaintFlags red_flags; + red_flags.setColor(SK_ColorRED); + green_recording->add_draw_rect_with_flags(viewport, red_flags); + PaintFlags green_flags; + green_flags.setColor(SK_ColorGREEN); + green_recording->add_draw_rect_with_flags(green_rect1, green_flags); + green_recording->add_draw_rect_with_flags(green_rect2, green_flags); green_recording->Rerecord(); scoped_refptr<FakeRasterSource> green_raster_source = FakeRasterSource::CreateFromRecordingSource(green_recording.get(), false); @@ -2984,13 +2984,13 @@ Region outside(layer_rect); outside.Subtract(gfx::ToEnclosingRect(union_layer_rect)); for (Region::Iterator iter(outside); iter.has_rect(); iter.next()) { - recording->add_draw_rect_with_paint(iter.rect(), red_paint); + recording->add_draw_rect_with_flags(iter.rect(), red_flags); } - PaintFlags blue_paint; - blue_paint.setColor(SK_ColorBLUE); - recording->add_draw_rectf_with_paint(blue_layer_rect1, blue_paint); - recording->add_draw_rectf_with_paint(blue_layer_rect2, blue_paint); + PaintFlags blue_flags; + blue_flags.setColor(SK_ColorBLUE); + recording->add_draw_rectf_with_flags(blue_layer_rect1, blue_flags); + recording->add_draw_rectf_with_flags(blue_layer_rect2, blue_flags); recording->Rerecord(); scoped_refptr<FakeRasterSource> raster_source = FakeRasterSource::CreateFromRecordingSource(recording.get(), false); @@ -3207,17 +3207,17 @@ bitmap.allocPixels( SkImageInfo::MakeN32Premul(mask_rect.width(), mask_rect.height())); SkCanvas canvas(bitmap); - PaintFlags paint; - paint.setStyle(PaintFlags::kStroke_Style); - paint.setStrokeWidth(SkIntToScalar(4)); - paint.setColor(SK_ColorGREEN); + PaintFlags flags; + flags.setStyle(PaintFlags::kStroke_Style); + flags.setStrokeWidth(SkIntToScalar(4)); + flags.setColor(SK_ColorGREEN); canvas.clear(SK_ColorWHITE); gfx::Rect inset_rect = rect; while (!inset_rect.IsEmpty()) { inset_rect.Inset(6, 6, 4, 4); canvas.drawRect(SkRect::MakeXYWH(inset_rect.x(), inset_rect.y(), inset_rect.width(), inset_rect.height()), - paint); + flags); inset_rect.Inset(6, 6, 4, 4); }
diff --git a/cc/paint/paint_flags.h b/cc/paint/paint_flags.h index f41e4a06..aa11245 100644 --- a/cc/paint/paint_flags.h +++ b/cc/paint/paint_flags.h
@@ -11,8 +11,8 @@ using PaintFlags = SkPaint; -inline const SkPaint& ToSkPaint(const PaintFlags& paint) { - return paint; +inline const SkPaint& ToSkPaint(const PaintFlags& flags) { + return flags; } } // namespace cc
diff --git a/cc/playback/OWNERS b/cc/playback/OWNERS new file mode 100644 index 0000000..bdd83bf --- /dev/null +++ b/cc/playback/OWNERS
@@ -0,0 +1 @@ +# COMPONENT: Internals>Compositing>Rasterization
diff --git a/cc/playback/drawing_display_item.cc b/cc/playback/drawing_display_item.cc index cec2980d..f040dfe 100644 --- a/cc/playback/drawing_display_item.cc +++ b/cc/playback/drawing_display_item.cc
@@ -21,9 +21,9 @@ DrawingDisplayItem::DrawingDisplayItem() : DisplayItem(DRAWING) {} -DrawingDisplayItem::DrawingDisplayItem(sk_sp<const PaintRecord> picture) +DrawingDisplayItem::DrawingDisplayItem(sk_sp<const PaintRecord> record) : DisplayItem(DRAWING) { - SetNew(std::move(picture)); + SetNew(std::move(record)); } DrawingDisplayItem::DrawingDisplayItem(const DrawingDisplayItem& item) @@ -34,8 +34,8 @@ DrawingDisplayItem::~DrawingDisplayItem() { } -void DrawingDisplayItem::SetNew(sk_sp<const PaintRecord> picture) { - picture_ = std::move(picture); +void DrawingDisplayItem::SetNew(sk_sp<const PaintRecord> record) { + picture_ = std::move(record); } DISABLE_CFI_PERF
diff --git a/cc/playback/drawing_display_item.h b/cc/playback/drawing_display_item.h index 871ad09d..ef5f4d57 100644 --- a/cc/playback/drawing_display_item.h +++ b/cc/playback/drawing_display_item.h
@@ -23,7 +23,7 @@ class CC_EXPORT DrawingDisplayItem : public DisplayItem { public: DrawingDisplayItem(); - explicit DrawingDisplayItem(sk_sp<const PaintRecord> picture); + explicit DrawingDisplayItem(sk_sp<const PaintRecord> record); explicit DrawingDisplayItem(const DrawingDisplayItem& item); ~DrawingDisplayItem() override; @@ -38,7 +38,7 @@ void CloneTo(DrawingDisplayItem* item) const; private: - void SetNew(sk_sp<const PaintRecord> picture); + void SetNew(sk_sp<const PaintRecord> record); sk_sp<const PaintRecord> picture_; };
diff --git a/cc/playback/image_hijack_canvas.cc b/cc/playback/image_hijack_canvas.cc index a5d596d7..8262d51 100644 --- a/cc/playback/image_hijack_canvas.cc +++ b/cc/playback/image_hijack_canvas.cc
@@ -105,6 +105,7 @@ SkPaint scratch_paint = paint; scratch_paint.setShader( decoded_image.image()->makeShader(xy[0], xy[1], &matrix)); + scratch_paint.setFilterQuality(decoded_image.filter_quality()); return ScopedImagePaint(std::move(scoped_lock), std::move(scratch_paint)); }
diff --git a/cc/playback/raster_source.cc b/cc/playback/raster_source.cc index 06b6788..6674ec669 100644 --- a/cc/playback/raster_source.cc +++ b/cc/playback/raster_source.cc
@@ -217,7 +217,7 @@ return recorder.finishRecordingAsPicture(); } -size_t RasterSource::GetPictureMemoryUsage() const { +size_t RasterSource::GetMemoryUsage() const { if (!display_list_) return 0; return display_list_->ApproximateMemoryUsage() +
diff --git a/cc/playback/raster_source.h b/cc/playback/raster_source.h index 29ca3889..ccfb613 100644 --- a/cc/playback/raster_source.h +++ b/cc/playback/raster_source.h
@@ -114,7 +114,7 @@ virtual void DidBeginTracing(); virtual void AsValueInto(base::trace_event::TracedValue* array) const; virtual sk_sp<SkPicture> GetFlattenedPicture(); - virtual size_t GetPictureMemoryUsage() const; + virtual size_t GetMemoryUsage() const; // Return true if LCD anti-aliasing may be used when rastering text. virtual bool CanUseLCDText() const;
diff --git a/cc/playback/raster_source_unittest.cc b/cc/playback/raster_source_unittest.cc index 4467f24..a0e0ab8e 100644 --- a/cc/playback/raster_source_unittest.cc +++ b/cc/playback/raster_source_unittest.cc
@@ -27,18 +27,18 @@ std::unique_ptr<FakeRecordingSource> recording_source = FakeRecordingSource::CreateFilledRecordingSource(layer_bounds); - SkPaint solid_paint; + PaintFlags solid_flags; SkColor solid_color = SkColorSetARGB(255, 12, 23, 34); - solid_paint.setColor(solid_color); + solid_flags.setColor(solid_color); SkColor non_solid_color = SkColorSetARGB(128, 45, 56, 67); SkColor color = SK_ColorTRANSPARENT; - SkPaint non_solid_paint; + PaintFlags non_solid_flags; bool is_solid_color = false; - non_solid_paint.setColor(non_solid_color); + non_solid_flags.setColor(non_solid_color); - recording_source->add_draw_rect_with_paint(gfx::Rect(layer_bounds), - solid_paint); + recording_source->add_draw_rect_with_flags(gfx::Rect(layer_bounds), + solid_flags); recording_source->Rerecord(); scoped_refptr<RasterSource> raster = @@ -55,8 +55,8 @@ } // Add one non-solid pixel and recreate the raster source. - recording_source->add_draw_rect_with_paint(gfx::Rect(50, 50, 1, 1), - non_solid_paint); + recording_source->add_draw_rect_with_flags(gfx::Rect(50, 50, 1, 1), + non_solid_flags); recording_source->Rerecord(); raster = RasterSource::CreateFromRecordingSource(recording_source.get(), false); @@ -100,16 +100,16 @@ SkColor solid_color = SkColorSetARGB(255, 12, 23, 34); SkColor color = SK_ColorTRANSPARENT; - SkPaint solid_paint; + PaintFlags solid_flags; bool is_solid_color = false; - solid_paint.setColor(solid_color); + solid_flags.setColor(solid_color); SkColor non_solid_color = SkColorSetARGB(128, 45, 56, 67); - SkPaint non_solid_paint; - non_solid_paint.setColor(non_solid_color); + PaintFlags non_solid_flags; + non_solid_flags.setColor(non_solid_color); - recording_source->add_draw_rect_with_paint(gfx::Rect(0, 0, 400, 400), - solid_paint); + recording_source->add_draw_rect_with_flags(gfx::Rect(0, 0, 400, 400), + solid_flags); recording_source->Rerecord(); scoped_refptr<RasterSource> raster = @@ -126,8 +126,8 @@ } // Add one non-solid pixel and recreate the raster source. - recording_source->add_draw_rect_with_paint(gfx::Rect(50, 50, 1, 1), - non_solid_paint); + recording_source->add_draw_rect_with_flags(gfx::Rect(50, 50, 1, 1), + non_solid_flags); recording_source->Rerecord(); raster = RasterSource::CreateFromRecordingSource(recording_source.get(), false); @@ -253,10 +253,10 @@ // Because the caller sets content opaque, it also promises that it // has at least filled in layer_bounds opaquely. - SkPaint white_paint; - white_paint.setColor(SK_ColorWHITE); - recording_source->add_draw_rect_with_paint(gfx::Rect(layer_bounds), - white_paint); + PaintFlags white_flags; + white_flags.setColor(SK_ColorWHITE); + recording_source->add_draw_rect_with_flags(gfx::Rect(layer_bounds), + white_flags); recording_source->Rerecord(); scoped_refptr<RasterSource> raster = @@ -318,10 +318,10 @@ recording_source->SetClearCanvasWithDebugColor(false); // First record everything as white. - SkPaint white_paint; - white_paint.setColor(SK_ColorWHITE); - recording_source->add_draw_rect_with_paint(gfx::Rect(layer_bounds), - white_paint); + PaintFlags white_flags; + white_flags.setColor(SK_ColorWHITE); + recording_source->add_draw_rect_with_flags(gfx::Rect(layer_bounds), + white_flags); recording_source->Rerecord(); scoped_refptr<RasterSource> raster = @@ -356,10 +356,10 @@ } // Re-record everything as black. - SkPaint black_paint; - black_paint.setColor(SK_ColorBLACK); - recording_source->add_draw_rect_with_paint(gfx::Rect(layer_bounds), - black_paint); + PaintFlags black_flags; + black_flags.setColor(SK_ColorBLACK); + recording_source->add_draw_rect_with_flags(gfx::Rect(layer_bounds), + black_flags); recording_source->Rerecord(); // Make a new RasterSource from the new recording. @@ -412,11 +412,11 @@ // First record everything as white. const unsigned alpha_dark = 10u; - SkPaint white_paint; - white_paint.setColor(SK_ColorWHITE); - white_paint.setAlpha(alpha_dark); - recording_source->add_draw_rect_with_paint(gfx::Rect(layer_bounds), - white_paint); + PaintFlags white_flags; + white_flags.setColor(SK_ColorWHITE); + white_flags.setAlpha(alpha_dark); + recording_source->add_draw_rect_with_flags(gfx::Rect(layer_bounds), + white_flags); recording_source->Rerecord(); scoped_refptr<RasterSource> raster = @@ -458,9 +458,9 @@ // Record everything as a slightly lighter white. const unsigned alpha_light = 18u; - white_paint.setAlpha(alpha_light); - recording_source_light->add_draw_rect_with_paint(gfx::Rect(layer_bounds), - white_paint); + white_flags.setAlpha(alpha_light); + recording_source_light->add_draw_rect_with_flags(gfx::Rect(layer_bounds), + white_flags); recording_source_light->Rerecord(); // Make a new RasterSource from the new recording. @@ -532,7 +532,7 @@ scoped_refptr<RasterSource> raster = RasterSource::CreateFromRecordingSource(recording_source.get(), false); - size_t total_memory_usage = raster->GetPictureMemoryUsage(); + size_t total_memory_usage = raster->GetMemoryUsage(); EXPECT_GE(total_memory_usage, kReportedMemoryUsageInBytes); EXPECT_LT(total_memory_usage, 2 * kReportedMemoryUsageInBytes); } @@ -552,19 +552,19 @@ gfx::Point(0, 0)); // 2. Cover everything in red. - SkPaint paint; - paint.setColor(SK_ColorRED); - recording_source->add_draw_rect_with_paint(gfx::Rect(size), paint); + PaintFlags flags; + flags.setColor(SK_ColorRED); + recording_source->add_draw_rect_with_flags(gfx::Rect(size), flags); // 3. Draw 4x4 green rects into every corner. - paint.setColor(SK_ColorGREEN); - recording_source->add_draw_rect_with_paint(gfx::Rect(0, 0, 4, 4), paint); - recording_source->add_draw_rect_with_paint( - gfx::Rect(size.width() - 4, 0, 4, 4), paint); - recording_source->add_draw_rect_with_paint( - gfx::Rect(0, size.height() - 4, 4, 4), paint); - recording_source->add_draw_rect_with_paint( - gfx::Rect(size.width() - 4, size.height() - 4, 4, 4), paint); + flags.setColor(SK_ColorGREEN); + recording_source->add_draw_rect_with_flags(gfx::Rect(0, 0, 4, 4), flags); + recording_source->add_draw_rect_with_flags( + gfx::Rect(size.width() - 4, 0, 4, 4), flags); + recording_source->add_draw_rect_with_flags( + gfx::Rect(0, size.height() - 4, 4, 4), flags); + recording_source->add_draw_rect_with_flags( + gfx::Rect(size.width() - 4, size.height() - 4, 4, 4), flags); recording_source->SetGenerateDiscardableImagesMetadata(true); recording_source->Rerecord();
diff --git a/cc/playback/recording_source_unittest.cc b/cc/playback/recording_source_unittest.cc index 2894882..9d7f6b6 100644 --- a/cc/playback/recording_source_unittest.cc +++ b/cc/playback/recording_source_unittest.cc
@@ -192,13 +192,13 @@ sk_sp<SkImage> non_discardable_image = SkImage::MakeFromBitmap(non_discardable_bitmap); - recording_source->add_draw_rect_with_paint(gfx::Rect(0, 0, 256, 256), + recording_source->add_draw_rect_with_flags(gfx::Rect(0, 0, 256, 256), simple_paint); - recording_source->add_draw_rect_with_paint(gfx::Rect(128, 128, 512, 512), + recording_source->add_draw_rect_with_flags(gfx::Rect(128, 128, 512, 512), simple_paint); - recording_source->add_draw_rect_with_paint(gfx::Rect(512, 0, 256, 256), + recording_source->add_draw_rect_with_flags(gfx::Rect(512, 0, 256, 256), simple_paint); - recording_source->add_draw_rect_with_paint(gfx::Rect(0, 512, 256, 256), + recording_source->add_draw_rect_with_flags(gfx::Rect(0, 512, 256, 256), simple_paint); recording_source->add_draw_image(non_discardable_image, gfx::Point(128, 0)); recording_source->add_draw_image(non_discardable_image, gfx::Point(0, 128));
diff --git a/cc/raster/OWNERS b/cc/raster/OWNERS new file mode 100644 index 0000000..bdd83bf --- /dev/null +++ b/cc/raster/OWNERS
@@ -0,0 +1 @@ +# COMPONENT: Internals>Compositing>Rasterization
diff --git a/cc/surfaces/OWNERS b/cc/surfaces/OWNERS index 5e47309..761d5f3 100644 --- a/cc/surfaces/OWNERS +++ b/cc/surfaces/OWNERS
@@ -1 +1,3 @@ jbauman@chromium.org + +# COMPONENT: Internals>Compositing>Quads
diff --git a/cc/surfaces/compositor_frame_sink_support.cc b/cc/surfaces/compositor_frame_sink_support.cc index 95222ed..95d7f09 100644 --- a/cc/surfaces/compositor_frame_sink_support.cc +++ b/cc/surfaces/compositor_frame_sink_support.cc
@@ -17,25 +17,31 @@ CompositorFrameSinkSupportClient* client, SurfaceManager* surface_manager, const FrameSinkId& frame_sink_id, - std::unique_ptr<Display> display, - std::unique_ptr<BeginFrameSource> display_begin_frame_source) + Display* display, + bool handles_frame_sink_id_invalidation, + bool needs_sync_points) : client_(client), surface_manager_(surface_manager), frame_sink_id_(frame_sink_id), - display_begin_frame_source_(std::move(display_begin_frame_source)), - display_(std::move(display)), + display_(display), surface_factory_(frame_sink_id_, surface_manager_, this), + handles_frame_sink_id_invalidation_(handles_frame_sink_id_invalidation), weak_factory_(this) { - surface_manager_->RegisterFrameSinkId(frame_sink_id_); - surface_manager_->RegisterSurfaceFactoryClient(frame_sink_id_, this); + if (handles_frame_sink_id_invalidation_) + surface_manager_->RegisterFrameSinkId(frame_sink_id_); - if (display_) { + surface_manager_->RegisterSurfaceFactoryClient(frame_sink_id_, this); + surface_factory_.set_needs_sync_points(needs_sync_points); + + if (display_) display_->Initialize(this, surface_manager_); - display_->SetVisible(true); - } } CompositorFrameSinkSupport::~CompositorFrameSinkSupport() { + // Unregister |this| as a BeginFrameObserver so that the BeginFrameSource does + // not call into |this| after it's deleted. + SetNeedsBeginFrame(false); + for (auto& child_frame_sink_id : child_frame_sinks_) { DCHECK(child_frame_sink_id.is_valid()); surface_manager_->UnregisterFrameSinkHierarchy(frame_sink_id_, @@ -46,7 +52,8 @@ // |surface_factory_|'s resources early on. surface_factory_.EvictSurface(); surface_manager_->UnregisterSurfaceFactoryClient(frame_sink_id_); - surface_manager_->InvalidateFrameSinkId(frame_sink_id_); + if (handles_frame_sink_id_invalidation_) + surface_manager_->InvalidateFrameSinkId(frame_sink_id_); } void CompositorFrameSinkSupport::EvictFrame() { @@ -62,14 +69,14 @@ const LocalSurfaceId& local_surface_id, CompositorFrame frame) { ++ack_pending_count_; - surface_factory_.SubmitCompositorFrame( - local_surface_id, std::move(frame), - base::Bind(&CompositorFrameSinkSupport::DidReceiveCompositorFrameAck, - weak_factory_.GetWeakPtr())); if (display_) { display_->SetLocalSurfaceId(local_surface_id, frame.metadata.device_scale_factor); } + surface_factory_.SubmitCompositorFrame( + local_surface_id, std::move(frame), + base::Bind(&CompositorFrameSinkSupport::DidReceiveCompositorFrameAck, + weak_factory_.GetWeakPtr())); } void CompositorFrameSinkSupport::Require(const LocalSurfaceId& local_surface_id, @@ -112,6 +119,10 @@ child_frame_sinks_.erase(it); } +void CompositorFrameSinkSupport::ForceReclaimResources() { + surface_factory_.ClearSurface(); +} + void CompositorFrameSinkSupport::DisplayOutputSurfaceLost() {} void CompositorFrameSinkSupport::DisplayWillDrawAndSwap(
diff --git a/cc/surfaces/compositor_frame_sink_support.h b/cc/surfaces/compositor_frame_sink_support.h index 8471bbd..eb63791e 100644 --- a/cc/surfaces/compositor_frame_sink_support.h +++ b/cc/surfaces/compositor_frame_sink_support.h
@@ -26,12 +26,16 @@ public SurfaceFactoryClient, public BeginFrameObserver { public: - CompositorFrameSinkSupport( - CompositorFrameSinkSupportClient* client, - SurfaceManager* surface_manager, - const FrameSinkId& frame_sink_id, - std::unique_ptr<Display> display, - std::unique_ptr<BeginFrameSource> display_begin_frame_source); + // |display| is nullptr if the CompositorFrameSinkSupport submits + // CompositorFrames to a offscreen texutre/bitmap instead of a + // DisplayCompositor. e.g. OffscreenCanvasCompositorFrameSink and + // GpuOffscreenCompositorFrameSink. + CompositorFrameSinkSupport(CompositorFrameSinkSupportClient* client, + SurfaceManager* surface_manager, + const FrameSinkId& frame_sink_id, + Display* display, + bool handles_frame_sink_id_invalidation, + bool needs_sync_points); ~CompositorFrameSinkSupport() override; @@ -46,8 +50,9 @@ void Satisfy(const SurfaceSequence& sequence); void AddChildFrameSink(const FrameSinkId& child_frame_sink_id); void RemoveChildFrameSink(const FrameSinkId& child_frame_sink_id); + void ForceReclaimResources(); - Display* display() { return display_.get(); } + Display* display() { return display_; } private: void DidReceiveCompositorFrameAck(); @@ -74,14 +79,8 @@ CompositorFrameSinkSupportClient* const client_; SurfaceManager* const surface_manager_; - const FrameSinkId frame_sink_id_; - - // GpuCompositorFrameSink holds a Display and its BeginFrameSource if it - // created with non-null gpu::SurfaceHandle. In the window server, the display - // root window's CompositorFrameSink will have a valid gpu::SurfaceHandle. - std::unique_ptr<BeginFrameSource> display_begin_frame_source_; - std::unique_ptr<Display> display_; + Display* const display_; SurfaceFactory surface_factory_; // Counts the number of CompositorFrames that have been submitted and have not @@ -101,6 +100,18 @@ // Whether or not a frame observer has been added. bool added_frame_observer_ = false; + // TODO(staraz): Remove this flag once ui::Compositor no longer needs + // RegisterFrameSinkId(). + // A SurfaceSequence's validity is bound to the lifetime of the parent + // FrameSink that created it. We track the lifetime of FrameSink's through + // RegisterFrameSinkId and InvalidateFrameSink. During startup and GPU + // restart, a SurfaceSequence created by the top most layer compositor may be + // used prior to the creation of the associated CompositorFrameSinkSupport. + // CompositorFrameSinkSupport is created asynchronously when a new GPU channel + // is established. Once we switch to SurfaceReferences, this ordering concern + // goes away and we can remove this bool. + const bool handles_frame_sink_id_invalidation_; + // The set of BeginFrame children of this CompositorFrameSink. std::unordered_set<FrameSinkId, FrameSinkIdHash> child_frame_sinks_;
diff --git a/cc/surfaces/direct_compositor_frame_sink.cc b/cc/surfaces/direct_compositor_frame_sink.cc index 10c37ee7..1fa4d8d 100644 --- a/cc/surfaces/direct_compositor_frame_sink.cc +++ b/cc/surfaces/direct_compositor_frame_sink.cc
@@ -29,14 +29,12 @@ shared_bitmap_manager), frame_sink_id_(frame_sink_id), surface_manager_(surface_manager), - display_(display), - factory_(frame_sink_id, surface_manager, this) { + display_(display) { DCHECK(thread_checker_.CalledOnValidThread()); capabilities_.can_force_reclaim_resources = true; // Display and DirectCompositorFrameSink share a GL context, so sync // points aren't needed when passing resources between them. capabilities_.delegated_sync_points_required = false; - factory_.set_needs_sync_points(false); } DirectCompositorFrameSink::DirectCompositorFrameSink( @@ -47,8 +45,7 @@ : CompositorFrameSink(std::move(vulkan_context_provider)), frame_sink_id_(frame_sink_id), surface_manager_(surface_manager), - display_(display), - factory_(frame_sink_id_, surface_manager, this) { + display_(display) { DCHECK(thread_checker_.CalledOnValidThread()); capabilities_.can_force_reclaim_resources = true; } @@ -64,26 +61,28 @@ if (!CompositorFrameSink::BindToClient(client)) return false; - surface_manager_->RegisterSurfaceFactoryClient(frame_sink_id_, this); - // We want the Display's output surface to hear about lost context, and since // this shares a context with it, we should not be listening for lost context // callbacks on the context here. if (auto* cp = context_provider()) cp->SetLostContextCallback(base::Closure()); + support_ = base::MakeUnique<CompositorFrameSinkSupport>( + this, surface_manager_, frame_sink_id_, display_, false, + capabilities_.delegated_sync_points_required); + + begin_frame_source_ = base::MakeUnique<ExternalBeginFrameSource>(this); + client_->SetBeginFrameSource(begin_frame_source_.get()); // Avoid initializing GL context here, as this should be sharing the // Display's context. - display_->Initialize(this, surface_manager_); + return true; } void DirectCompositorFrameSink::DetachFromClient() { - // Unregister the SurfaceFactoryClient here instead of the dtor so that only - // one client is alive for this namespace at any given time. - surface_manager_->UnregisterSurfaceFactoryClient(frame_sink_id_); - factory_.EvictSurface(); - + client_->SetBeginFrameSource(nullptr); + begin_frame_source_.reset(); + support_.reset(); CompositorFrameSink::DetachFromClient(); } @@ -93,30 +92,12 @@ delegated_local_surface_id_ = surface_id_allocator_.GenerateId(); last_swap_frame_size_ = frame_size; } - display_->SetLocalSurfaceId(delegated_local_surface_id_, - frame.metadata.device_scale_factor); - - factory_.SubmitCompositorFrame( - delegated_local_surface_id_, std::move(frame), - base::Bind(&DirectCompositorFrameSink::DidDrawCallback, - base::Unretained(this))); + support_->SubmitCompositorFrame(delegated_local_surface_id_, + std::move(frame)); } void DirectCompositorFrameSink::ForceReclaimResources() { - if (delegated_local_surface_id_.is_valid()) - factory_.ClearSurface(); -} - -void DirectCompositorFrameSink::ReturnResources( - const ReturnedResourceArray& resources) { - if (client_) - client_->ReclaimResources(resources); -} - -void DirectCompositorFrameSink::SetBeginFrameSource( - BeginFrameSource* begin_frame_source) { - DCHECK(client_); - client_->SetBeginFrameSource(begin_frame_source); + support_->ForceReclaimResources(); } void DirectCompositorFrameSink::DisplayOutputSurfaceLost() { @@ -136,8 +117,29 @@ // be drawn. } +void DirectCompositorFrameSink::DidReceiveCompositorFrameAck() { + client_->DidReceiveCompositorFrameAck(); +} + +void DirectCompositorFrameSink::OnBeginFrame(const BeginFrameArgs& args) { + begin_frame_source_->OnBeginFrame(args); +} + +void DirectCompositorFrameSink::ReclaimResources( + const ReturnedResourceArray& resources) { + client_->ReclaimResources(resources); +} + +void DirectCompositorFrameSink::WillDrawSurface() { + // TODO(staraz): Implement this. +} + void DirectCompositorFrameSink::DidDrawCallback() { client_->DidReceiveCompositorFrameAck(); } +void DirectCompositorFrameSink::OnNeedsBeginFrames(bool needs_begin_frame) { + support_->SetNeedsBeginFrame(needs_begin_frame); +} + } // namespace cc
diff --git a/cc/surfaces/direct_compositor_frame_sink.h b/cc/surfaces/direct_compositor_frame_sink.h index 609f381..db0a009 100644 --- a/cc/surfaces/direct_compositor_frame_sink.h +++ b/cc/surfaces/direct_compositor_frame_sink.h
@@ -8,6 +8,8 @@ #include "base/macros.h" #include "base/threading/thread_checker.h" #include "cc/output/compositor_frame_sink.h" +#include "cc/surfaces/compositor_frame_sink_support.h" +#include "cc/surfaces/compositor_frame_sink_support_client.h" #include "cc/surfaces/display_client.h" #include "cc/surfaces/surface_factory.h" #include "cc/surfaces/surface_factory_client.h" @@ -23,8 +25,9 @@ // client's frame being the root surface of the Display. class CC_SURFACES_EXPORT DirectCompositorFrameSink : public CompositorFrameSink, - public SurfaceFactoryClient, - public NON_EXPORTED_BASE(DisplayClient) { + public NON_EXPORTED_BASE(DisplayClient), + public CompositorFrameSinkSupportClient, + public ExternalBeginFrameSourceClient { public: // The underlying Display, SurfaceManager, and SurfaceIdAllocator must outlive // this class. @@ -49,30 +52,36 @@ void SubmitCompositorFrame(CompositorFrame frame) override; void ForceReclaimResources() override; - // SurfaceFactoryClient implementation. - void ReturnResources(const ReturnedResourceArray& resources) override; - void SetBeginFrameSource(BeginFrameSource* begin_frame_source) override; - // DisplayClient implementation. void DisplayOutputSurfaceLost() override; void DisplayWillDrawAndSwap(bool will_draw_and_swap, const RenderPassList& render_passes) override; void DisplayDidDrawAndSwap() override; + // CompositorFrameSinkSupportClient implementation: + void DidReceiveCompositorFrameAck() override; + void OnBeginFrame(const BeginFrameArgs& args) override; + void ReclaimResources(const ReturnedResourceArray& resources) override; + void WillDrawSurface() override; + private: void DidDrawCallback(); + // ExternalBeginFrameSouceClient implementation: + void OnNeedsBeginFrames(bool needs_begin_frames) override; + // This class is only meant to be used on a single thread. base::ThreadChecker thread_checker_; const FrameSinkId frame_sink_id_; LocalSurfaceId delegated_local_surface_id_; - SurfaceManager* surface_manager_; SurfaceIdAllocator surface_id_allocator_; + SurfaceManager* surface_manager_; Display* display_; - SurfaceFactory factory_; gfx::Size last_swap_frame_size_; bool is_lost_ = false; + std::unique_ptr<CompositorFrameSinkSupport> support_; + std::unique_ptr<ExternalBeginFrameSource> begin_frame_source_; DISALLOW_COPY_AND_ASSIGN(DirectCompositorFrameSink); };
diff --git a/cc/test/fake_content_layer_client.cc b/cc/test/fake_content_layer_client.cc index 74e9691..906ee5e 100644 --- a/cc/test/fake_content_layer_client.cc +++ b/cc/test/fake_content_layer_client.cc
@@ -18,13 +18,13 @@ FakeContentLayerClient::ImageData::ImageData(sk_sp<const SkImage> img, const gfx::Point& point, - const PaintFlags& paint) - : image(std::move(img)), point(point), paint(paint) {} + const PaintFlags& flags) + : image(std::move(img)), point(point), flags(flags) {} FakeContentLayerClient::ImageData::ImageData(sk_sp<const SkImage> img, const gfx::Transform& transform, - const PaintFlags& paint) - : image(std::move(img)), transform(transform), paint(paint) {} + const PaintFlags& flags) + : image(std::move(img)), transform(transform), flags(flags) {} FakeContentLayerClient::ImageData::ImageData(const ImageData& other) = default; @@ -48,8 +48,6 @@ scoped_refptr<DisplayItemList> FakeContentLayerClient::PaintContentsToDisplayList( PaintingControlSetting painting_control) { - // Cached picture is used because unit tests expect to be able to - // use GatherPixelRefs. auto display_list = make_scoped_refptr(new DisplayItemList); display_list->SetRetainVisualRectsForTesting(true); PaintRecorder recorder; @@ -57,10 +55,10 @@ for (RectPaintVector::const_iterator it = draw_rects_.begin(); it != draw_rects_.end(); ++it) { const gfx::RectF& draw_rect = it->first; - const PaintFlags& paint = it->second; + const PaintFlags& flags = it->second; PaintCanvas* canvas = recorder.beginRecording(gfx::RectFToSkRect(draw_rect)); - canvas->drawRect(gfx::RectFToSkRect(draw_rect), paint); + canvas->drawRect(gfx::RectFToSkRect(draw_rect), flags); display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>( ToEnclosingRect(draw_rect), recorder.finishRecordingAsPicture()); } @@ -74,7 +72,7 @@ PaintCanvas* canvas = recorder.beginRecording(it->image->width(), it->image->height()); canvas->drawImage(it->image.get(), it->point.x(), it->point.y(), - &it->paint); + &it->flags); display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>( PaintableRegion(), recorder.finishRecordingAsPicture()); if (!it->transform.IsIdentity()) { @@ -86,11 +84,11 @@ gfx::Rect draw_rect = PaintableRegion(); bool red = true; while (!draw_rect.IsEmpty()) { - PaintFlags paint; - paint.setColor(red ? SK_ColorRED : SK_ColorBLUE); + PaintFlags flags; + flags.setColor(red ? SK_ColorRED : SK_ColorBLUE); PaintCanvas* canvas = recorder.beginRecording(gfx::RectToSkRect(draw_rect)); - canvas->drawIRect(gfx::RectToSkIRect(draw_rect), paint); + canvas->drawIRect(gfx::RectToSkIRect(draw_rect), flags); display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>( draw_rect, recorder.finishRecordingAsPicture()); draw_rect.Inset(1, 1);
diff --git a/cc/test/fake_content_layer_client.h b/cc/test/fake_content_layer_client.h index 8087d76..d35f8b7 100644 --- a/cc/test/fake_content_layer_client.h +++ b/cc/test/fake_content_layer_client.h
@@ -26,16 +26,16 @@ struct ImageData { ImageData(sk_sp<const SkImage> image, const gfx::Point& point, - const PaintFlags& paint); + const PaintFlags& flags); ImageData(sk_sp<const SkImage> image, const gfx::Transform& transform, - const PaintFlags& paint); + const PaintFlags& flags); ImageData(const ImageData& other); ~ImageData(); sk_sp<const SkImage> image; gfx::Point point; gfx::Transform transform; - PaintFlags paint; + PaintFlags flags; }; FakeContentLayerClient(); @@ -51,25 +51,25 @@ fill_with_nonsolid_color_ = nonsolid; } - void add_draw_rect(const gfx::Rect& rect, const PaintFlags& paint) { - draw_rects_.push_back(std::make_pair(gfx::RectF(rect), paint)); + void add_draw_rect(const gfx::Rect& rect, const PaintFlags& flags) { + draw_rects_.push_back(std::make_pair(gfx::RectF(rect), flags)); } - void add_draw_rectf(const gfx::RectF& rect, const PaintFlags& paint) { - draw_rects_.push_back(std::make_pair(rect, paint)); + void add_draw_rectf(const gfx::RectF& rect, const PaintFlags& flags) { + draw_rects_.push_back(std::make_pair(rect, flags)); } void add_draw_image(sk_sp<const SkImage> image, const gfx::Point& point, - const PaintFlags& paint) { - ImageData data(std::move(image), point, paint); + const PaintFlags& flags) { + ImageData data(std::move(image), point, flags); draw_images_.push_back(data); } void add_draw_image_with_transform(sk_sp<const SkImage> image, const gfx::Transform& transform, - const PaintFlags& paint) { - ImageData data(std::move(image), transform, paint); + const PaintFlags& flags) { + ImageData data(std::move(image), transform, flags); draw_images_.push_back(data); }
diff --git a/cc/test/fake_raster_source.cc b/cc/test/fake_raster_source.cc index af4faa8..a3e92c9 100644 --- a/cc/test/fake_raster_source.cc +++ b/cc/test/fake_raster_source.cc
@@ -24,15 +24,15 @@ auto recording_source = FakeRecordingSource::CreateFilledRecordingSource(size); - PaintFlags red_paint; - red_paint.setColor(SK_ColorRED); - recording_source->add_draw_rect_with_paint(gfx::Rect(size), red_paint); + PaintFlags red_flags; + red_flags.setColor(SK_ColorRED); + recording_source->add_draw_rect_with_flags(gfx::Rect(size), red_flags); - PaintFlags salmon_pink_paint; - salmon_pink_paint.setColor(SK_ColorRED); - salmon_pink_paint.setAlpha(128); - recording_source->add_draw_rect_with_paint(gfx::Rect(size), - salmon_pink_paint); + PaintFlags salmon_pink_flags; + salmon_pink_flags.setColor(SK_ColorRED); + salmon_pink_flags.setAlpha(128); + recording_source->add_draw_rect_with_flags(gfx::Rect(size), + salmon_pink_flags); recording_source->Rerecord(); @@ -45,15 +45,15 @@ auto recording_source = FakeRecordingSource::CreateFilledRecordingSource(size); - PaintFlags red_paint; - red_paint.setColor(SK_ColorRED); - recording_source->add_draw_rect_with_paint(gfx::Rect(size), red_paint); + PaintFlags red_flags; + red_flags.setColor(SK_ColorRED); + recording_source->add_draw_rect_with_flags(gfx::Rect(size), red_flags); gfx::Size smaller_size(size.width() - 10, size.height() - 10); - PaintFlags green_paint; - green_paint.setColor(SK_ColorGREEN); - recording_source->add_draw_rect_with_paint(gfx::Rect(smaller_size), - green_paint); + PaintFlags green_flags; + green_flags.setColor(SK_ColorGREEN); + recording_source->add_draw_rect_with_flags(gfx::Rect(smaller_size), + green_flags); recording_source->Rerecord(); @@ -65,9 +65,9 @@ auto recording_source = FakeRecordingSource::CreateFilledRecordingSource(size); - PaintFlags red_paint; - red_paint.setColor(SK_ColorRED); - recording_source->add_draw_rect_with_paint(gfx::Rect(size), red_paint); + PaintFlags red_flags; + red_flags.setColor(SK_ColorRED); + recording_source->add_draw_rect_with_flags(gfx::Rect(size), red_flags); recording_source->Rerecord(); auto raster_source = make_scoped_refptr(new FakeRasterSource(recording_source.get(), false)); @@ -84,15 +84,15 @@ auto recording_source = FakeRecordingSource::CreateRecordingSource(recorded_viewport, size); - PaintFlags red_paint; - red_paint.setColor(SK_ColorRED); - recording_source->add_draw_rect_with_paint(gfx::Rect(size), red_paint); + PaintFlags red_flags; + red_flags.setColor(SK_ColorRED); + recording_source->add_draw_rect_with_flags(gfx::Rect(size), red_flags); gfx::Size smaller_size(size.width() - 10, size.height() - 10); - PaintFlags green_paint; - green_paint.setColor(SK_ColorGREEN); - recording_source->add_draw_rect_with_paint(gfx::Rect(smaller_size), - green_paint); + PaintFlags green_flags; + green_flags.setColor(SK_ColorGREEN); + recording_source->add_draw_rect_with_flags(gfx::Rect(smaller_size), + green_flags); recording_source->Rerecord(); recording_source->SetRecordedViewport(recorded_viewport);
diff --git a/cc/test/fake_recording_source.h b/cc/test/fake_recording_source.h index bd827e6..9a007fd 100644 --- a/cc/test/fake_recording_source.h +++ b/cc/test/fake_recording_source.h
@@ -78,40 +78,40 @@ } void add_draw_rect(const gfx::Rect& rect) { - client_.add_draw_rect(rect, default_paint_); + client_.add_draw_rect(rect, default_flags_); } - void add_draw_rect_with_paint(const gfx::Rect& rect, - const PaintFlags& paint) { - client_.add_draw_rect(rect, paint); + void add_draw_rect_with_flags(const gfx::Rect& rect, + const PaintFlags& flags) { + client_.add_draw_rect(rect, flags); } void add_draw_rectf(const gfx::RectF& rect) { - client_.add_draw_rectf(rect, default_paint_); + client_.add_draw_rectf(rect, default_flags_); } - void add_draw_rectf_with_paint(const gfx::RectF& rect, - const PaintFlags& paint) { - client_.add_draw_rectf(rect, paint); + void add_draw_rectf_with_flags(const gfx::RectF& rect, + const PaintFlags& flags) { + client_.add_draw_rectf(rect, flags); } void add_draw_image(sk_sp<const SkImage> image, const gfx::Point& point) { - client_.add_draw_image(std::move(image), point, default_paint_); + client_.add_draw_image(std::move(image), point, default_flags_); } void add_draw_image_with_transform(sk_sp<const SkImage> image, const gfx::Transform& transform) { client_.add_draw_image_with_transform(std::move(image), transform, - default_paint_); + default_flags_); } - void add_draw_image_with_paint(sk_sp<const SkImage> image, + void add_draw_image_with_flags(sk_sp<const SkImage> image, const gfx::Point& point, - const PaintFlags& paint) { - client_.add_draw_image(std::move(image), point, paint); + const PaintFlags& flags) { + client_.add_draw_image(std::move(image), point, flags); } - void set_default_paint(const PaintFlags& paint) { default_paint_ = paint; } + void set_default_flags(const PaintFlags& flags) { default_flags_ = flags; } void set_reported_memory_usage(size_t reported_memory_usage) { client_.set_reported_memory_usage(reported_memory_usage); @@ -133,7 +133,7 @@ private: FakeContentLayerClient client_; - PaintFlags default_paint_; + PaintFlags default_flags_; base::WaitableEvent* playback_allowed_event_; };
diff --git a/cc/test/solid_color_content_layer_client.cc b/cc/test/solid_color_content_layer_client.cc index 16330cc9..cb8e13c27 100644 --- a/cc/test/solid_color_content_layer_client.cc +++ b/cc/test/solid_color_content_layer_client.cc
@@ -30,22 +30,22 @@ canvas->clear(SK_ColorTRANSPARENT); if (border_size_ != 0) { - PaintFlags paint; - paint.setStyle(PaintFlags::kFill_Style); - paint.setColor(border_color_); + PaintFlags flags; + flags.setStyle(PaintFlags::kFill_Style); + flags.setColor(border_color_); canvas->drawRect( SkRect::MakeXYWH(clip.x(), clip.y(), clip.width(), clip.height()), - paint); + flags); } - PaintFlags paint; - paint.setStyle(PaintFlags::kFill_Style); - paint.setColor(color_); + PaintFlags flags; + flags.setStyle(PaintFlags::kFill_Style); + flags.setColor(color_); canvas->drawRect( SkRect::MakeXYWH(clip.x() + border_size_, clip.y() + border_size_, clip.width() - 2 * border_size_, clip.height() - 2 * border_size_), - paint); + flags); auto display_list = make_scoped_refptr(new DisplayItemList); display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
diff --git a/cc/test/test_gles2_interface.cc b/cc/test/test_gles2_interface.cc index a8b27c2..8a48d67 100644 --- a/cc/test/test_gles2_interface.cc +++ b/cc/test/test_gles2_interface.cc
@@ -277,15 +277,6 @@ test_context_->destroyImageCHROMIUM(image_id); } -GLuint TestGLES2Interface::CreateGpuMemoryBufferImageCHROMIUM( - GLsizei width, - GLsizei height, - GLenum internalformat, - GLenum usage) { - return test_context_->createGpuMemoryBufferImageCHROMIUM( - width, height, internalformat, usage); -} - void TestGLES2Interface::BindTexImage2DCHROMIUM(GLenum target, GLint image_id) { test_context_->bindTexImage2DCHROMIUM(target, image_id); }
diff --git a/cc/test/test_gles2_interface.h b/cc/test/test_gles2_interface.h index e432bc1..20faa12 100644 --- a/cc/test/test_gles2_interface.h +++ b/cc/test/test_gles2_interface.h
@@ -105,10 +105,6 @@ GLsizei height, GLenum internalformat) override; void DestroyImageCHROMIUM(GLuint image_id) override; - GLuint CreateGpuMemoryBufferImageCHROMIUM(GLsizei width, - GLsizei height, - GLenum internalformat, - GLenum usage) override; void BindTexImage2DCHROMIUM(GLenum target, GLint image_id) override; void ReleaseTexImage2DCHROMIUM(GLenum target, GLint image_id) override; void FramebufferRenderbuffer(GLenum target,
diff --git a/cc/tiles/tile_manager_unittest.cc b/cc/tiles/tile_manager_unittest.cc index d1346be..8e4d4ae 100644 --- a/cc/tiles/tile_manager_unittest.cc +++ b/cc/tiles/tile_manager_unittest.cc
@@ -1423,19 +1423,19 @@ std::unique_ptr<FakeRecordingSource> recording_source = FakeRecordingSource::CreateFilledRecordingSource(layer_bounds); - PaintFlags solid_paint; + PaintFlags solid_flags; SkColor solid_color = SkColorSetARGB(255, 12, 23, 34); - solid_paint.setColor(solid_color); - recording_source->add_draw_rect_with_paint(gfx::Rect(layer_bounds), - solid_paint); + solid_flags.setColor(solid_color); + recording_source->add_draw_rect_with_flags(gfx::Rect(layer_bounds), + solid_flags); // Create non solid tile as well, otherwise tilings wouldnt be created. SkColor non_solid_color = SkColorSetARGB(128, 45, 56, 67); - PaintFlags non_solid_paint; - non_solid_paint.setColor(non_solid_color); + PaintFlags non_solid_flags; + non_solid_flags.setColor(non_solid_color); - recording_source->add_draw_rect_with_paint(gfx::Rect(0, 0, 10, 10), - non_solid_paint); + recording_source->add_draw_rect_with_flags(gfx::Rect(0, 0, 10, 10), + non_solid_flags); recording_source->Rerecord(); scoped_refptr<RasterSource> raster_source = @@ -1636,9 +1636,9 @@ recording_source->SetBackgroundColor(SK_ColorTRANSPARENT); recording_source->SetRequiresClear(true); recording_source->SetClearCanvasWithDebugColor(false); - PaintFlags paint; - paint.setColor(SK_ColorGREEN); - recording_source->add_draw_rect_with_paint(gfx::Rect(size), paint); + PaintFlags flags; + flags.setColor(SK_ColorGREEN); + recording_source->add_draw_rect_with_flags(gfx::Rect(size), flags); recording_source->add_draw_image(std::move(blue_image), gfx::Point()); recording_source->Rerecord(); scoped_refptr<RasterSource> raster = @@ -1728,11 +1728,11 @@ std::unique_ptr<FakeRecordingSource> active_tree_recording_source = FakeRecordingSource::CreateFilledRecordingSource(layer_bounds); - PaintFlags solid_paint; + PaintFlags solid_flags; SkColor solid_color = SkColorSetARGB(255, 12, 23, 34); - solid_paint.setColor(solid_color); - active_tree_recording_source->add_draw_rect_with_paint( - gfx::Rect(layer_bounds), solid_paint); + solid_flags.setColor(solid_color); + active_tree_recording_source->add_draw_rect_with_flags( + gfx::Rect(layer_bounds), solid_flags); active_tree_recording_source->Rerecord(); @@ -1740,11 +1740,11 @@ std::unique_ptr<FakeRecordingSource> pending_tree_recording_source = FakeRecordingSource::CreateFilledRecordingSource(layer_bounds); SkColor non_solid_color = SkColorSetARGB(128, 45, 56, 67); - PaintFlags non_solid_paint; - non_solid_paint.setColor(non_solid_color); + PaintFlags non_solid_flags; + non_solid_flags.setColor(non_solid_color); - pending_tree_recording_source->add_draw_rect_with_paint( - gfx::Rect(5, 5, 10, 10), non_solid_paint); + pending_tree_recording_source->add_draw_rect_with_flags( + gfx::Rect(5, 5, 10, 10), non_solid_flags); pending_tree_recording_source->Rerecord(); scoped_refptr<RasterSource> active_tree_raster_source = @@ -1981,24 +1981,24 @@ solid_color_recording_source_ = FakeRecordingSource::CreateFilledRecordingSource(layer_bounds); - SkPaint solid_paint; + PaintFlags solid_flags; SkColor solid_color = SkColorSetARGB(255, 12, 23, 34); - solid_paint.setColor(solid_color); - solid_color_recording_source_->add_draw_rect_with_paint( - gfx::Rect(layer_bounds), solid_paint); + solid_flags.setColor(solid_color); + solid_color_recording_source_->add_draw_rect_with_flags( + gfx::Rect(layer_bounds), solid_flags); solid_color_recording_source_->Rerecord(); recording_source_ = FakeRecordingSource::CreateFilledRecordingSource(layer_bounds); SkColor non_solid_color = SkColorSetARGB(128, 45, 56, 67); - SkPaint non_solid_paint; - non_solid_paint.setColor(non_solid_color); + PaintFlags non_solid_flags; + non_solid_flags.setColor(non_solid_color); for (int i = 0; i < 100; ++i) { for (int j = 0; j < 100; ++j) { - recording_source_->add_draw_rect_with_paint( - gfx::Rect(10 * i, 10 * j, 5, 5), non_solid_paint); + recording_source_->add_draw_rect_with_flags( + gfx::Rect(10 * i, 10 * j, 5, 5), non_solid_flags); } } recording_source_->Rerecord();
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 722b0539..ecf60cf9 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -1061,16 +1061,16 @@ input_handler_client_->ReconcileElasticOverscrollAndRootScroll(); if (const char* client_name = GetClientNameForMetrics()) { - size_t total_picture_memory = 0; + size_t total_memory = 0; for (const PictureLayerImpl* layer : active_tree()->picture_layers()) - total_picture_memory += layer->GetRasterSource()->GetPictureMemoryUsage(); - if (total_picture_memory != 0) { + total_memory += layer->GetRasterSource()->GetMemoryUsage(); + if (total_memory != 0) { // GetClientNameForMetrics only returns one non-null value over the // lifetime of the process, so this histogram name is runtime constant. UMA_HISTOGRAM_COUNTS( base::StringPrintf("Compositing.%s.PictureMemoryUsageKb", client_name), - base::saturated_cast<int>(total_picture_memory / 1024)); + base::saturated_cast<int>(total_memory / 1024)); } // GetClientNameForMetrics only returns one non-null value over the lifetime // of the process, so this histogram name is runtime constant.
diff --git a/cc/trees/layer_tree_host_pixeltest_masks.cc b/cc/trees/layer_tree_host_pixeltest_masks.cc index 7d9c3cd..7a43574 100644 --- a/cc/trees/layer_tree_host_pixeltest_masks.cc +++ b/cc/trees/layer_tree_host_pixeltest_masks.cc
@@ -43,19 +43,19 @@ PaintCanvas* canvas = recorder.beginRecording(gfx::RectToSkRect(gfx::Rect(bounds_))); - PaintFlags paint; - paint.setStyle(PaintFlags::kStroke_Style); - paint.setStrokeWidth(SkIntToScalar(2)); - paint.setColor(SK_ColorWHITE); + PaintFlags flags; + flags.setStyle(PaintFlags::kStroke_Style); + flags.setStrokeWidth(SkIntToScalar(2)); + flags.setColor(SK_ColorWHITE); canvas->clear(SK_ColorTRANSPARENT); gfx::Rect inset_rect(bounds_); while (!inset_rect.IsEmpty()) { inset_rect.Inset(3, 3, 2, 2); canvas->drawRect( - SkRect::MakeXYWH(inset_rect.x(), inset_rect.y(), - inset_rect.width(), inset_rect.height()), - paint); + SkRect::MakeXYWH(inset_rect.x(), inset_rect.y(), inset_rect.width(), + inset_rect.height()), + flags); inset_rect.Inset(3, 3, 2, 2); } @@ -165,18 +165,18 @@ PaintCanvas* canvas = recorder.beginRecording(gfx::RectToSkRect(gfx::Rect(bounds_))); - PaintFlags paint; - paint.setStyle(PaintFlags::kStroke_Style); - paint.setStrokeWidth(SkIntToScalar(4)); - paint.setColor(color_); + PaintFlags flags; + flags.setStyle(PaintFlags::kStroke_Style); + flags.setStrokeWidth(SkIntToScalar(4)); + flags.setColor(color_); canvas->clear(SK_ColorTRANSPARENT); if (vertical_) { for (int i = 4; i < bounds_.width(); i += 16) { - canvas->drawLine(i, 0, i, bounds_.height(), paint); + canvas->drawLine(i, 0, i, bounds_.height(), flags); } } else { for (int i = 4; i < bounds_.height(); i += 16) { - canvas->drawLine(0, i, bounds_.width(), i, paint); + canvas->drawLine(0, i, bounds_.width(), i, flags); } } @@ -208,14 +208,12 @@ PaintCanvas* canvas = recorder.beginRecording(gfx::RectToSkRect(gfx::Rect(bounds_))); - PaintFlags paint; - paint.setStyle(PaintFlags::kFill_Style); - paint.setColor(SK_ColorWHITE); + PaintFlags flags; + flags.setStyle(PaintFlags::kFill_Style); + flags.setColor(SK_ColorWHITE); canvas->clear(SK_ColorTRANSPARENT); - canvas->drawCircle(bounds_.width() / 2, - bounds_.height() / 2, - bounds_.width() / 4, - paint); + canvas->drawCircle(bounds_.width() / 2, bounds_.height() / 2, + bounds_.width() / 4, flags); auto display_list = make_scoped_refptr(new DisplayItemList); display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
diff --git a/cc/trees/layer_tree_host_pixeltest_scrollbars.cc b/cc/trees/layer_tree_host_pixeltest_scrollbars.cc index 69fec99..683a5d49 100644 --- a/cc/trees/layer_tree_host_pixeltest_scrollbars.cc +++ b/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
@@ -53,17 +53,17 @@ void PaintPart(PaintCanvas* canvas, ScrollbarPart part, const gfx::Rect& content_rect) override { - PaintFlags paint; - paint.setStyle(PaintFlags::kStroke_Style); - paint.setStrokeWidth(SkIntToScalar(paint_scale_)); - paint.setColor(color_); + PaintFlags flags; + flags.setStyle(PaintFlags::kStroke_Style); + flags.setStrokeWidth(SkIntToScalar(paint_scale_)); + flags.setColor(color_); gfx::Rect inset_rect = content_rect; while (!inset_rect.IsEmpty()) { int big = paint_scale_ + 2; int small = paint_scale_; inset_rect.Inset(big, big, small, small); - canvas->drawRect(RectToSkRect(inset_rect), paint); + canvas->drawRect(RectToSkRect(inset_rect), flags); inset_rect.Inset(big, big, small, small); } }
diff --git a/cc/trees/layer_tree_host_pixeltest_synchronous.cc b/cc/trees/layer_tree_host_pixeltest_synchronous.cc index 6f73e08..16ce2cf 100644 --- a/cc/trees/layer_tree_host_pixeltest_synchronous.cc +++ b/cc/trees/layer_tree_host_pixeltest_synchronous.cc
@@ -35,9 +35,9 @@ FakeContentLayerClient client; client.set_bounds(bounds); - PaintFlags green_paint; - green_paint.setColor(SkColorSetARGB(255, 0, 255, 0)); - client.add_draw_rect(gfx::Rect(bounds), green_paint); + PaintFlags green_flags; + green_flags.setColor(SkColorSetARGB(255, 0, 255, 0)); + client.add_draw_rect(gfx::Rect(bounds), green_flags); scoped_refptr<PictureLayer> root = PictureLayer::Create(&client); root->SetBounds(bounds); root->SetIsDrawable(true); @@ -66,9 +66,9 @@ FakeContentLayerClient client; client.set_bounds(bounds); - PaintFlags green_paint; - green_paint.setColor(SkColorSetARGB(255, 0, 255, 0)); - client.add_draw_rect(gfx::Rect(bounds), green_paint); + PaintFlags green_flags; + green_flags.setColor(SkColorSetARGB(255, 0, 255, 0)); + client.add_draw_rect(gfx::Rect(bounds), green_flags); scoped_refptr<PictureLayer> root = PictureLayer::Create(&client); root->SetBounds(bounds); client.set_bounds(bounds);
diff --git a/cc/trees/layer_tree_host_pixeltest_tiles.cc b/cc/trees/layer_tree_host_pixeltest_tiles.cc index 0a279c0e..6eaa10aa 100644 --- a/cc/trees/layer_tree_host_pixeltest_tiles.cc +++ b/cc/trees/layer_tree_host_pixeltest_tiles.cc
@@ -122,13 +122,13 @@ gfx::Rect blue_rect = blue_top_ ? top : bottom; gfx::Rect yellow_rect = blue_top_ ? bottom : top; - PaintFlags paint; - paint.setStyle(PaintFlags::kFill_Style); + PaintFlags flags; + flags.setStyle(PaintFlags::kFill_Style); - paint.setColor(SK_ColorBLUE); - canvas->drawRect(gfx::RectToSkRect(blue_rect), paint); - paint.setColor(SK_ColorYELLOW); - canvas->drawRect(gfx::RectToSkRect(yellow_rect), paint); + flags.setColor(SK_ColorBLUE); + canvas->drawRect(gfx::RectToSkRect(blue_rect), flags); + flags.setColor(SK_ColorYELLOW); + canvas->drawRect(gfx::RectToSkRect(yellow_rect), flags); display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>( PaintableRegion(), recorder.finishRecordingAsPicture());
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc index a8b7086..f59b200 100644 --- a/cc/trees/layer_tree_host_unittest_context.cc +++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -610,9 +610,9 @@ root_->SetIsDrawable(true); // Paint non-solid color. - PaintFlags paint; - paint.setColor(SkColorSetARGB(100, 80, 200, 200)); - client_.add_draw_rect(gfx::Rect(5, 5), paint); + PaintFlags flags; + flags.setColor(SkColorSetARGB(100, 80, 200, 200)); + client_.add_draw_rect(gfx::Rect(5, 5), flags); layer_ = FakePictureLayer::Create(&client_); layer_->SetBounds(gfx::Size(10, 10)); @@ -689,9 +689,9 @@ void SetupTree() override { // Paint non-solid color. - PaintFlags paint; - paint.setColor(SkColorSetARGB(100, 80, 200, 200)); - client_.add_draw_rect(gfx::Rect(5, 5), paint); + PaintFlags flags; + flags.setColor(SkColorSetARGB(100, 80, 200, 200)); + client_.add_draw_rect(gfx::Rect(5, 5), flags); scoped_refptr<FakePictureLayer> picture_layer = FakePictureLayer::Create(&client_); @@ -1603,9 +1603,9 @@ : public LayerTreeTest { protected: void SetupTree() override { - PaintFlags paint; + PaintFlags flags; client_.set_fill_with_nonsolid_color(true); - client_.add_draw_rect(gfx::Rect(5, 5), paint); + client_.add_draw_rect(gfx::Rect(5, 5), flags); scoped_refptr<FakePictureLayer> picture_layer = FakePictureLayer::Create(&client_);
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn index 4fe0d58..3e696f0e 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn
@@ -1348,6 +1348,7 @@ "//chrome/browser/resources:settings_resources", "//chrome/browser/resources:task_scheduler_internals_resources", "//chrome/browser/resources:translate_internals_resources", + "//chrome/browser/resources:webapks_ui_resources", ] if (is_chromeos) {
diff --git a/chrome/VERSION b/chrome/VERSION index 3998baa4..10fd3e5 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=58 MINOR=0 -BUILD=3006 +BUILD=3007 PATCH=0
diff --git a/chrome/android/java/res/drawable-v21/most_visited_item_highlight.xml b/chrome/android/java/res/drawable-v21/tile_view_highlight.xml similarity index 84% rename from chrome/android/java/res/drawable-v21/most_visited_item_highlight.xml rename to chrome/android/java/res/drawable-v21/tile_view_highlight.xml index c8c76cf..328ce31 100644 --- a/chrome/android/java/res/drawable-v21/most_visited_item_highlight.xml +++ b/chrome/android/java/res/drawable-v21/tile_view_highlight.xml
@@ -9,6 +9,6 @@ <item android:id="@android:id/mask" - android:drawable="@drawable/most_visited_item_highlight_mask"/> + android:drawable="@drawable/tile_view_highlight_mask"/> </ripple> \ No newline at end of file
diff --git a/chrome/android/java/res/drawable/most_visited_item_highlight.xml b/chrome/android/java/res/drawable/tile_view_highlight.xml similarity index 89% rename from chrome/android/java/res/drawable/most_visited_item_highlight.xml rename to chrome/android/java/res/drawable/tile_view_highlight.xml index a3f673f..6b68eb8 100644 --- a/chrome/android/java/res/drawable/most_visited_item_highlight.xml +++ b/chrome/android/java/res/drawable/tile_view_highlight.xml
@@ -5,5 +5,5 @@ found in the LICENSE file. --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="true" android:drawable="@drawable/most_visited_item_highlight_plain" /> + <item android:state_pressed="true" android:drawable="@drawable/tile_view_highlight_plain" /> </selector>
diff --git a/chrome/android/java/res/drawable/most_visited_item_highlight_mask.xml b/chrome/android/java/res/drawable/tile_view_highlight_mask.xml similarity index 83% rename from chrome/android/java/res/drawable/most_visited_item_highlight_mask.xml rename to chrome/android/java/res/drawable/tile_view_highlight_mask.xml index b94de7a3..a0f9166 100644 --- a/chrome/android/java/res/drawable/most_visited_item_highlight_mask.xml +++ b/chrome/android/java/res/drawable/tile_view_highlight_mask.xml
@@ -8,5 +8,5 @@ <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="#000" /> - <corners android:radius="@dimen/most_visited_bg_corner_radius" /> + <corners android:radius="@dimen/tile_view_bg_corner_radius" /> </shape> \ No newline at end of file
diff --git a/chrome/android/java/res/drawable/most_visited_item_highlight_plain.xml b/chrome/android/java/res/drawable/tile_view_highlight_plain.xml similarity index 83% rename from chrome/android/java/res/drawable/most_visited_item_highlight_plain.xml rename to chrome/android/java/res/drawable/tile_view_highlight_plain.xml index c608838..19983a7 100644 --- a/chrome/android/java/res/drawable/most_visited_item_highlight_plain.xml +++ b/chrome/android/java/res/drawable/tile_view_highlight_plain.xml
@@ -8,5 +8,5 @@ <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="#a0ffffff" /> - <corners android:radius="@dimen/most_visited_bg_corner_radius" /> + <corners android:radius="@dimen/tile_view_bg_corner_radius" /> </shape> \ No newline at end of file
diff --git a/chrome/android/java/res/layout/new_tab_page_layout.xml b/chrome/android/java/res/layout/new_tab_page_layout.xml index 0af0820..aca5715 100644 --- a/chrome/android/java/res/layout/new_tab_page_layout.xml +++ b/chrome/android/java/res/layout/new_tab_page_layout.xml
@@ -102,26 +102,26 @@ android:layout_weight="0" android:visibility="invisible" /> - <!-- Most visited items --> - <org.chromium.chrome.browser.ntp.MostVisitedLayout - android:id="@+id/most_visited_layout" + <!-- Site suggestion tiles --> + <org.chromium.chrome.browser.suggestions.TileGridLayout + android:id="@+id/tile_grid_layout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="16dp" android:layout_marginStart="12dp" android:layout_marginEnd="12dp" android:layout_gravity="center_horizontal" - android:paddingTop="@dimen/most_visited_layout_padding_top" + android:paddingTop="@dimen/tile_grid_layout_padding_top" android:paddingBottom="4dp" /> - <!-- Most visited items placeholder --> + <!-- Site suggestions tile grid placeholder --> <ViewStub - android:id="@+id/most_visited_placeholder_stub" + android:id="@+id/tile_grid_placeholder_stub" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" - android:inflatedId="@+id/most_visited_placeholder" - android:layout="@layout/most_visited_placeholder" /> + android:inflatedId="@+id/tile_grid_placeholder" + android:layout="@layout/new_tab_page_tile_grid_placeholder" /> <!-- Bottom spacer --> <View
diff --git a/chrome/android/java/res/layout/most_visited_placeholder.xml b/chrome/android/java/res/layout/new_tab_page_tile_grid_placeholder.xml similarity index 100% rename from chrome/android/java/res/layout/most_visited_placeholder.xml rename to chrome/android/java/res/layout/new_tab_page_tile_grid_placeholder.xml
diff --git a/chrome/android/java/res/layout/suggestions_site_tile_grid.xml b/chrome/android/java/res/layout/suggestions_site_tile_grid.xml index f0dffd80..c95ef0b 100644 --- a/chrome/android/java/res/layout/suggestions_site_tile_grid.xml +++ b/chrome/android/java/res/layout/suggestions_site_tile_grid.xml
@@ -3,14 +3,14 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<org.chromium.chrome.browser.ntp.MostVisitedLayout +<org.chromium.chrome.browser.suggestions.TileGridLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/most_visited_layout" + android:id="@+id/tile_grid_layout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="16dp" android:layout_marginStart="12dp" android:layout_marginEnd="12dp" android:layout_gravity="center_horizontal" - android:paddingTop="@dimen/most_visited_layout_padding_top" + android:paddingTop="@dimen/tile_grid_layout_padding_top" android:paddingBottom="4dp" />
diff --git a/chrome/android/java/res/layout/most_visited_item.xml b/chrome/android/java/res/layout/tile_view.xml similarity index 61% rename from chrome/android/java/res/layout/most_visited_item.xml rename to chrome/android/java/res/layout/tile_view.xml index 8863267..f820e8f 100644 --- a/chrome/android/java/res/layout/most_visited_item.xml +++ b/chrome/android/java/res/layout/tile_view.xml
@@ -3,19 +3,19 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<!-- A most visited item, for display on the new tab page. --> -<org.chromium.chrome.browser.ntp.MostVisitedItemView +<!-- A site suggestion tile. --> +<org.chromium.chrome.browser.suggestions.TileView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:chrome="http://schemas.android.com/apk/res-auto" - android:layout_width="@dimen/most_visited_tile_width" + android:layout_width="@dimen/tile_view_width" android:layout_height="wrap_content" android:paddingStart="4dp" android:paddingEnd="4dp" > <ImageView - android:id="@+id/most_visited_icon" - android:layout_width="@dimen/most_visited_icon_size" - android:layout_height="@dimen/most_visited_icon_size" + android:id="@+id/tile_view_icon" + android:layout_width="@dimen/tile_view_icon_size" + android:layout_height="@dimen/tile_view_icon_size" android:layout_marginStart="12dp" android:layout_marginEnd="12dp" android:layout_marginTop="12dp" @@ -23,25 +23,25 @@ <org.chromium.chrome.browser.widget.TintedImageView android:id="@+id/offline_badge" - android:layout_width="@dimen/most_visited_offline_badge_size" - android:layout_height="@dimen/most_visited_offline_badge_size" + android:layout_width="@dimen/tile_view_offline_badge_size" + android:layout_height="@dimen/tile_view_offline_badge_size" android:layout_marginStart="48dp" android:visibility="gone" android:background="@drawable/offline_badge_background" android:contentDescription="@string/accessibility_ntp_offline_badge" - chrome:tint="@color/most_visited_offline_badge_tint" + chrome:tint="@color/tile_view_offline_badge_tint" android:src="@drawable/offline_pin_round" /> <View - android:layout_width="@dimen/most_visited_icon_size" - android:layout_height="@dimen/most_visited_icon_size" + android:layout_width="@dimen/tile_view_icon_size" + android:layout_height="@dimen/tile_view_icon_size" android:layout_marginStart="12dp" android:layout_marginEnd="12dp" android:layout_marginTop="12dp" - android:background="@drawable/most_visited_item_highlight" /> + android:background="@drawable/tile_view_highlight" /> <TextView - android:id="@+id/most_visited_title" + android:id="@+id/tile_view_title" android:layout_width="72dp" android:layout_height="wrap_content" android:layout_marginTop="66dp" @@ -49,7 +49,7 @@ android:gravity="center_horizontal" android:lines="2" android:lineSpacingMultiplier="1.17" - android:textColor="@color/most_visited_text" + android:textColor="@color/tile_view_text" android:textSize="12sp" /> -</org.chromium.chrome.browser.ntp.MostVisitedItemView> +</org.chromium.chrome.browser.suggestions.TileView>
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml index 375ac06..a7f3933e 100644 --- a/chrome/android/java/res/values/colors.xml +++ b/chrome/android/java/res/values/colors.xml
@@ -113,9 +113,9 @@ <color name="snippets_list_header_text_color">#646464</color> <color name="snippets_headline_text_color">#333333</color> - <!-- Most Visited colors. --> - <color name="most_visited_text">#6f6f6f</color> - <color name="most_visited_offline_badge_tint">#4285f4</color> + <!-- Site suggestion tile colors. --> + <color name="tile_view_text">#6f6f6f</color> + <color name="tile_view_offline_badge_tint">#4285f4</color> <!-- Contextual Search colors --> <color name="contextual_search_promo_text_color">#333333</color>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml index 5af6ce8..1e457ba02 100644 --- a/chrome/android/java/res/values/dimens.xml +++ b/chrome/android/java/res/values/dimens.xml
@@ -263,17 +263,17 @@ <dimen name="omnibox_suggestion_multiline_text_vertical_padding">10dp</dimen> <!-- NTP dimensions --> - <dimen name="most_visited_bg_corner_radius">2dp</dimen> - <dimen name="most_visited_layout_max_width">504dp</dimen> - <dimen name="most_visited_layout_padding_top">8dp</dimen> - <dimen name="most_visited_layout_no_logo_padding_top">20dp</dimen> - <dimen name="most_visited_layout_bleed">8dp</dimen> - <dimen name="most_visited_vertical_spacing">3dp</dimen> - <dimen name="most_visited_min_horizontal_spacing">4dp</dimen> - <dimen name="most_visited_max_horizontal_spacing">16dp</dimen> - <dimen name="most_visited_tile_width">80dp</dimen> - <dimen name="most_visited_icon_size">48dp</dimen> - <dimen name="most_visited_offline_badge_size">24dp</dimen> + <dimen name="tile_grid_layout_max_width">504dp</dimen> + <dimen name="tile_grid_layout_padding_top">8dp</dimen> + <dimen name="tile_grid_layout_no_logo_padding_top">20dp</dimen> + <dimen name="tile_grid_layout_bleed">8dp</dimen> + <dimen name="tile_grid_layout_vertical_spacing">3dp</dimen> + <dimen name="tile_grid_layout_min_horizontal_spacing">4dp</dimen> + <dimen name="tile_grid_layout_max_horizontal_spacing">16dp</dimen> + <dimen name="tile_view_bg_corner_radius">2dp</dimen> + <dimen name="tile_view_width">80dp</dimen> + <dimen name="tile_view_icon_size">48dp</dimen> + <dimen name="tile_view_offline_badge_size">24dp</dimen> <dimen name="ntp_logo_height">116dp</dimen> <dimen name="ntp_search_box_height">62dp</dimen> <dimen name="ntp_search_box_shadow_width">4dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java index ca9f1157..ff97c0d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -128,6 +128,7 @@ import org.chromium.chrome.browser.webapps.AddToHomescreenManager; import org.chromium.chrome.browser.widget.BottomSheet; import org.chromium.chrome.browser.widget.ControlContainer; +import org.chromium.chrome.browser.widget.FadingBackgroundView; import org.chromium.components.bookmarks.BookmarkId; import org.chromium.content.browser.ContentVideoView; import org.chromium.content.browser.ContentViewCore; @@ -150,6 +151,8 @@ import java.util.List; import java.util.concurrent.TimeUnit; +import javax.annotation.Nullable; + /** * A {@link AsyncInitializationActivity} that builds and manages a {@link CompositorViewHolder} * and associated classes. @@ -341,6 +344,11 @@ if (mBottomSheet != null) { mBottomSheet.setTabModelSelector(mTabModelSelector); mBottomSheet.setFullscreenManager(mFullscreenManager); + + FadingBackgroundView fadingView = + (FadingBackgroundView) findViewById(R.id.fading_focus_target); + mBottomSheet.addObserver(fadingView); + fadingView.addObserver(mBottomSheet); } ((BottomContainer) findViewById(R.id.bottom_container)).initialize(mFullscreenManager); } @@ -1953,6 +1961,30 @@ return (useLowEndTheme ? R.style.MainTheme_LowEnd : R.style.MainTheme); } + /** + * Looks up the Chrome activity of the given web contents. This can be null. Should never be + * cached, because web contents can change activities, e.g., when user selects "Open in Chrome" + * menu item. + * + * @param webContents The web contents for which to lookup the Chrome activity. + * @return Possibly null Chrome activity that should never be cached. + */ + @Nullable public static ChromeActivity fromWebContents(@Nullable WebContents webContents) { + if (webContents == null) return null; + + ContentViewCore contentViewCore = ContentViewCore.fromWebContents(webContents); + if (contentViewCore == null) return null; + + WindowAndroid window = contentViewCore.getWindowAndroid(); + if (window == null) return null; + + Activity activity = window.getActivity().get(); + if (activity == null) return null; + if (!(activity instanceof ChromeActivity)) return null; + + return (ChromeActivity) activity; + } + private void setLowEndTheme() { if (getThemeId() == R.style.MainTheme_LowEnd) setTheme(R.style.MainTheme_LowEnd); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java index 6e6102d..5da682f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -80,6 +80,7 @@ public static final String TABS_IN_CBD = "TabsInCBD"; public static final String IMPROVED_A2HS = "ImprovedA2HS"; public static final String NO_CREDIT_CARD_ABORT = "NoCreditCardAbort"; + public static final String NTP_CONDENSED_LAYOUT = "NTPCondensedLayout"; public static final String NTP_FAKE_OMNIBOX_TEXT = "NTPFakeOmniboxText"; public static final String NTP_FOREIGN_SESSIONS_SUGGESTIONS = "NTPForeignSessionsSuggestions"; public static final String NTP_OFFLINE_PAGES_FEATURE_NAME = "NTPOfflinePages";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java index 86c6914..a5b974f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java
@@ -9,6 +9,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; @@ -22,6 +23,7 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.AsyncTask; +import android.support.annotation.NonNull; import android.text.TextUtils; import android.util.Base64; @@ -34,6 +36,7 @@ import org.chromium.blink_public.platform.WebDisplayMode; import org.chromium.chrome.R; import org.chromium.chrome.browser.webapps.ChromeWebApkHost; +import org.chromium.chrome.browser.webapps.WebApkInfo; import org.chromium.chrome.browser.webapps.WebappActivity; import org.chromium.chrome.browser.webapps.WebappAuthenticator; import org.chromium.chrome.browser.webapps.WebappDataStorage; @@ -45,6 +48,7 @@ import org.chromium.webapk.lib.client.WebApkValidator; import java.io.ByteArrayOutputStream; +import java.util.ArrayList; import java.util.List; /** @@ -658,5 +662,48 @@ return null; } + /** + * Calls the native |callbackPointer| with lists of information on all installed WebAPKs. + * + * @param callbackPointer Callback to call with the information on the WebAPKs found. + */ + @CalledByNative + public static void retrieveWebApks(long callbackPointer) { + List<String> shortNames = new ArrayList<>(); + List<String> packageNames = new ArrayList<>(); + List<Integer> shellApkVersions = new ArrayList<>(); + List<Integer> versionCodes = new ArrayList<>(); + + Context context = ContextUtils.getApplicationContext(); + PackageManager packageManager = context.getPackageManager(); + for (PackageInfo packageInfo : packageManager.getInstalledPackages(0)) { + if (WebApkValidator.isValidWebApk(context, packageInfo.packageName)) { + // Pass non-null URL parameter so that {@link WebApkInfo#create()} + // return value is non-null + WebApkInfo webApkInfo = + WebApkInfo.create(packageInfo.packageName, "", ShortcutSource.UNKNOWN); + if (webApkInfo != null) { + shortNames.add(webApkInfo.shortName()); + packageNames.add(webApkInfo.webApkPackageName()); + shellApkVersions.add(webApkInfo.shellApkVersion()); + versionCodes.add(packageInfo.versionCode); + } + } + } + nativeOnWebApksRetrieved(callbackPointer, shortNames.toArray(new String[0]), + packageNames.toArray(new String[0]), integerListToIntArray(shellApkVersions), + integerListToIntArray(versionCodes)); + } + + private static int[] integerListToIntArray(@NonNull List<Integer> list) { + int[] array = new int[list.size()]; + for (int i = 0; i < list.size(); i++) { + array[i] = list.get(i); + } + return array; + } + private static native void nativeOnWebappDataStored(long callbackPointer); + private static native void nativeOnWebApksRetrieved(long callbackPointer, String[] shortNames, + String[] packageName, int[] shellApkVersions, int[] versionCodes); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java index 3a88d09..e4c3de2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
@@ -100,7 +100,6 @@ private ChromeFullscreenManager mFullscreenManager; private View mAccessibilityView; private CompositorAccessibilityProvider mNodeProvider; - private float mLastContentOffset; /** The toolbar control container. **/ private ControlContainer mControlContainer; @@ -455,7 +454,6 @@ */ public void onStart() { if (mFullscreenManager != null) { - mLastContentOffset = mFullscreenManager.getContentOffset(); mFullscreenManager.addListener(this); } requestRender(); @@ -470,7 +468,6 @@ @Override public void onContentOffsetChanged(float offset) { - mLastContentOffset = offset; onViewportChanged(); } @@ -518,10 +515,6 @@ } private void onViewportChanged() { - // TODO(changwan): check if this can be merged with setContentMotionEventOffsets. - if (mTabVisible != null && mTabVisible.getContentViewCore() != null) { - mTabVisible.getContentViewCore().setSmartClipOffsets(0, (int) -mLastContentOffset); - } if (mLayoutManager != null) mLayoutManager.onViewportChanged(); } @@ -678,7 +671,6 @@ public void setFullscreenHandler(ChromeFullscreenManager fullscreen) { mFullscreenManager = fullscreen; if (mFullscreenManager != null) { - mLastContentOffset = mFullscreenManager.getContentOffset(); mFullscreenManager.addListener(this); } onViewportChanged();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java index f7882d9..6db719eae2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
@@ -170,6 +170,16 @@ // AsyncInitializationActivity: @Override + protected Bundle transformSavedInstanceStateForOnCreate(Bundle savedInstanceState) { + // We pass null to Activity.onCreate() so that it doesn't automatically restore + // the FragmentManager state - as that may cause fragments to be loaded that have + // dependencies on native before native has been loaded (and then crash). Instead, + // these fragments will be recreated manually by us and their progression restored + // from |mFreProperties| which we still get from getSavedInstanceState() below. + return null; + } + + @Override public void setContentView() { Bundle savedInstanceState = getSavedInstanceState(); if (savedInstanceState != null) { @@ -281,6 +291,17 @@ } @Override + public void onRestoreInstanceState(Bundle state) { + // Don't automatically restore state here. This is a counterpart to the override + // of transformSavedInstanceStateForOnCreate() as the two need to be consistent. + // The default implementation of this would restore the state of the views, which + // would otherwise cause a crash in ViewPager used to manage fragments - as it + // expects consistency between the states restored by onCreate() and this method. + // Activity doesn't check for null on the parameter, so pass an empty bundle. + super.onRestoreInstanceState(new Bundle()); + } + + @Override public void onPause() { super.onPause(); flushPersistentData();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java index b53c8c4..3d124dd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
@@ -244,7 +244,7 @@ return; } - super.onCreate(savedInstanceState); + super.onCreate(transformSavedInstanceStateForOnCreate(savedInstanceState)); mOnCreateTimestampMs = SystemClock.elapsedRealtime(); mOnCreateTimestampUptimeMs = SystemClock.uptimeMillis(); mSavedInstanceState = savedInstanceState; @@ -253,6 +253,14 @@ } /** + * Allows subclasses to override the instance state passed to super.onCreate(). + * The original instance state will still be available via getSavedInstanceState(). + */ + protected Bundle transformSavedInstanceStateForOnCreate(Bundle savedInstanceState) { + return savedInstanceState; + } + + /** * Whether or not the Activity was started up via a valid Intent. */ protected boolean isStartedUpCorrectly(Intent intent) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java index 2c51eb9..83ec9847 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
@@ -35,6 +35,7 @@ import org.chromium.chrome.browser.services.AccountsChangedReceiver; import org.chromium.chrome.browser.services.GoogleServicesManager; import org.chromium.chrome.browser.sync.SyncController; +import org.chromium.chrome.browser.webapps.ChromeWebApkHost; import org.chromium.components.signin.AccountManagerHelper; import org.chromium.content.common.ContentSwitches; import org.chromium.printing.PrintDocumentAdapterWrapper; @@ -256,5 +257,12 @@ } } }); + + DeferredStartupHandler.getInstance().addDeferredTask(new Runnable() { + @Override + public void run() { + ChromeWebApkHost.initCanUseGooglePlayToInstallWebApk(); + } + }); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedItemView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedItemView.java deleted file mode 100644 index cffb2e64..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedItemView.java +++ /dev/null
@@ -1,67 +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. - -package org.chromium.chrome.browser.ntp; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.support.annotation.Nullable; -import android.util.AttributeSet; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.TextView; - -import org.chromium.chrome.R; - -/** - * The view for a most visited item. Displays the title of the page beneath a large icon. If a large - * icon isn't available, displays a rounded rectangle with a single letter in its place. - */ -public class MostVisitedItemView extends FrameLayout { - private String mUrl; - - /** - * Constructor for inflating from XML. - */ - public MostVisitedItemView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - /** - * Sets the title text. - */ - public void setTitle(String title) { - ((TextView) findViewById(R.id.most_visited_title)).setText(title); - } - - /** - * Sets the icon, or null to clear it. - */ - public void setIcon(@Nullable Drawable icon) { - ((ImageView) findViewById(R.id.most_visited_icon)).setImageDrawable(icon); - } - - /** - * Sets whether the page is available offline. - */ - public void setOfflineAvailable(boolean offlineAvailable) { - findViewById(R.id.offline_badge).setVisibility( - offlineAvailable ? View.VISIBLE : View.INVISIBLE); - } - - /** - * Sets the site URL. This is used to identify the view. - */ - public void setUrl(String url) { - mUrl = url; - } - - /** - * Gets the site URL. This is used to identify the view. - */ - public String getUrl() { - return mUrl; - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NativePageFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NativePageFactory.java index 9996540..a851b64 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NativePageFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NativePageFactory.java
@@ -14,6 +14,7 @@ import org.chromium.chrome.browser.UrlConstants; import org.chromium.chrome.browser.bookmarks.BookmarkPage; import org.chromium.chrome.browser.download.DownloadPage; +import org.chromium.chrome.browser.history.HistoryManagerUtils; import org.chromium.chrome.browser.history.HistoryPage; import org.chromium.chrome.browser.physicalweb.PhysicalWebDiagnosticsPage; import org.chromium.chrome.browser.tab.Tab; @@ -84,7 +85,11 @@ } else if (UrlConstants.DOWNLOADS_HOST.equals(host)) { return NativePageType.DOWNLOADS; } else if (UrlConstants.HISTORY_HOST.equals(host)) { - return NativePageType.HISTORY; + if (HistoryManagerUtils.isAndroidHistoryManagerEnabled()) { + return NativePageType.HISTORY; + } else { + return NativePageType.NONE; + } } else if (UrlConstants.RECENT_TABS_HOST.equals(host) && !isIncognito) { return NativePageType.RECENT_TABS; } else if (UrlConstants.PHYSICAL_WEB_DIAGNOSTICS_HOST.equals(host)) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java index 0e5e08b..403c496f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -41,7 +41,6 @@ import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.search_engines.TemplateUrlService; import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrlServiceObserver; -import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController; import org.chromium.chrome.browser.suggestions.SuggestionsMetricsReporter; import org.chromium.chrome.browser.suggestions.SuggestionsNavigationDelegate; import org.chromium.chrome.browser.suggestions.SuggestionsNavigationDelegateImpl; @@ -102,7 +101,6 @@ private final TileGroup.Delegate mTileGroupDelegate; private TabObserver mTabObserver; - private SnackbarController mMostVisitedItemRemovedController; private LogoBridge mLogoBridge; private boolean mSearchProviderHasLogo; private String mOnLogoClickUrl; @@ -631,9 +629,6 @@ mSnippetsBridge.destroy(); mSnippetsBridge = null; } - if (mMostVisitedItemRemovedController != null) { - mTab.getSnackbarManager().dismissSnackbars(mMostVisitedItemRemovedController); - } mNewTabPageManager.onDestroy(); mTileGroupDelegate.destroy(); TemplateUrlService.getInstance().removeObserver(this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java index 184f52fe..cc762a0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
@@ -12,10 +12,12 @@ import android.widget.LinearLayout; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ntp.NewTabPageUma.NTPLayoutResult; import org.chromium.chrome.browser.ntp.cards.CardsVariationParameters; import org.chromium.chrome.browser.ntp.cards.NewTabPageRecyclerView; import org.chromium.chrome.browser.ntp.snippets.SnippetsConfig; +import org.chromium.chrome.browser.suggestions.TileGridLayout; /** * Layout for the new tab page. This positions the page elements in the correct vertical positions. @@ -35,7 +37,7 @@ private final int mMiddleSpacerIdealHeight; private final int mBottomSpacerIdealHeight; private final int mTotalSpacerIdealHeight; - private final int mMostVisitedLayoutBleed; + private final int mTileGridLayoutBleed; private final int mPeekingCardHeight; private final int mTabStripHeight; private final int mFieldTrialLayoutAdjustment; @@ -52,7 +54,7 @@ private LogoView mSearchProviderLogoView; private View mSearchBoxView; - private MostVisitedLayout mMostVisitedLayout; + private TileGridLayout mTileGridLayout; private boolean mLayoutResultRecorded; @@ -67,7 +69,7 @@ mMiddleSpacerIdealHeight = Math.round(density * MIDDLE_SPACER_HEIGHT_DP); mBottomSpacerIdealHeight = Math.round(density * BOTTOM_SPACER_HEIGHT_DP); mTotalSpacerIdealHeight = Math.round(density * TOTAL_SPACER_HEIGHT_DP); - mMostVisitedLayoutBleed = res.getDimensionPixelSize(R.dimen.most_visited_layout_bleed); + mTileGridLayoutBleed = res.getDimensionPixelSize(R.dimen.tile_grid_layout_bleed); mPeekingCardHeight = SnippetsConfig.isIncreasedCardVisibilityEnabled() ? res.getDimensionPixelSize(R.dimen.snippets_peeking_card_peek_amount) : res.getDimensionPixelSize(R.dimen.snippets_padding); @@ -87,7 +89,7 @@ mSearchBoxSpacer = findViewById(R.id.search_box_spacer); mSearchProviderLogoView = (LogoView) findViewById(R.id.search_provider_logo); mSearchBoxView = findViewById(R.id.search_box); - mMostVisitedLayout = (MostVisitedLayout) findViewById(R.id.most_visited_layout); + mTileGridLayout = (TileGridLayout) findViewById(R.id.tile_grid_layout); } /** @@ -120,7 +122,7 @@ mSearchBoxSpacer.setVisibility(View.GONE); // Remove the extra spacing before measuring because it might not be needed anymore. - mMostVisitedLayout.setExtraVerticalSpacing(0); + mTileGridLayout.setExtraVerticalSpacing(0); super.onMeasure(widthMeasureSpec, heightMeasureSpec); @@ -128,31 +130,31 @@ int spaceToFill = mParentViewportHeight - mPeekingCardHeight - mTabStripHeight; @NTPLayoutResult int layoutResult; - // We need to make sure we have just enough space to show the peeking card. - if (getMeasuredHeight() > spaceToFill) { + if (ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_CONDENSED_LAYOUT)) { + layoutResult = NewTabPageUma.NTP_LAYOUT_CONDENSED; + } else if (getMeasuredHeight() > spaceToFill) { + // We need to make sure we have just enough space to show the peeking card. layoutResult = NewTabPageUma.NTP_LAYOUT_DOES_NOT_FIT; // We don't have enough, we will push the peeking card completely below the fold - // and let MostVisited get cut to make it clear that the page is scrollable. - if (mMostVisitedLayout.getChildCount() > 0) { + // and let the tile grid get cut to make it clear that the page is scrollable. + if (mTileGridLayout.getChildCount() > 0) { // Add some extra space if needed (the 'bleed' is the amount of the layout that // will be cut off by the bottom of the screen). int currentBleed = getMeasuredHeight() - mParentViewportHeight - mTabStripHeight; - int minimumBleed = - (int) (mMostVisitedLayout.getChildAt(0).getMeasuredHeight() * 0.44); + int minimumBleed = (int) (mTileGridLayout.getChildAt(0).getMeasuredHeight() * 0.44); if (currentBleed < minimumBleed) { int extraBleed = minimumBleed - currentBleed; mLogoSpacer.getLayoutParams().height = (int) (extraBleed * 0.25); mLogoSpacer.setVisibility(View.INVISIBLE); mSearchBoxSpacer.getLayoutParams().height = (int) (extraBleed * 0.25); mSearchBoxSpacer.setVisibility(View.INVISIBLE); - mMostVisitedLayout.setExtraVerticalSpacing((int) (extraBleed * 0.5)); + mTileGridLayout.setExtraVerticalSpacing((int) (extraBleed * 0.5)); super.onMeasure(widthMeasureSpec, heightMeasureSpec); layoutResult = NewTabPageUma.NTP_LAYOUT_DOES_NOT_FIT_PUSH_MOST_LIKELY; } } - } else { hasSpaceForPeekingCard = true; // We leave more than or just enough space needed for the peeking card. Redistribute @@ -185,9 +187,9 @@ NewTabPageRecyclerView recyclerView = (NewTabPageRecyclerView) getParent(); recyclerView.setHasSpaceForPeekingCard(hasSpaceForPeekingCard); - // The first few runs of this method occur before the Most Visited layout has loaded it's + // The first few runs of this method occur before the tile grid layout has loaded its // contents. We want to record what the user sees when the layout has stabilized. - if (mMostVisitedLayout.getChildCount() > 0 && !mLayoutResultRecorded) { + if (mTileGridLayout.getChildCount() > 0 && !mLayoutResultRecorded) { mLayoutResultRecorded = true; NewTabPageUma.recordNTPLayoutResult(layoutResult); } @@ -197,8 +199,8 @@ * Makes the Search Box and Logo as wide as Most Visited. */ private void unifyElementWidths() { - if (mMostVisitedLayout.getVisibility() != GONE) { - final int width = mMostVisitedLayout.getMeasuredWidth() - mMostVisitedLayoutBleed; + if (mTileGridLayout.getVisibility() != GONE) { + final int width = mTileGridLayout.getMeasuredWidth() - mTileGridLayoutBleed; measureExactly(mSearchBoxView, width + mSearchboxShadowWidth, mSearchBoxView.getMeasuredHeight()); measureExactly(mSearchProviderLogoView,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageUma.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageUma.java index 9b5087e..deb2e7d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageUma.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageUma.java
@@ -34,93 +34,136 @@ // Possible actions taken by the user on the NTP. These values are also defined in // histograms.xml. WARNING: these values must stay in sync with histograms.xml. - // User performed a search using the omnibox + /** User performed a search using the omnibox. */ private static final int ACTION_SEARCHED_USING_OMNIBOX = 0; - // User navigated to Google search homepage using the omnibox + + /** User navigated to Google search homepage using the omnibox. */ private static final int ACTION_NAVIGATED_TO_GOOGLE_HOMEPAGE = 1; - // User navigated to any other page using the omnibox + + /** User navigated to any other page using the omnibox. */ private static final int ACTION_NAVIGATED_USING_OMNIBOX = 2; - // User opened a most visited tile + + /** User opened a most visited tile. */ public static final int ACTION_OPENED_MOST_VISITED_TILE = 3; - // User opened the recent tabs manager + + /** User opened the recent tabs manager. */ public static final int ACTION_OPENED_RECENT_TABS_MANAGER = 4; - // User opened the history manager + + /** User opened the history manager. */ public static final int ACTION_OPENED_HISTORY_MANAGER = 5; - // User opened the bookmarks manager + + /** User opened the bookmarks manager. */ public static final int ACTION_OPENED_BOOKMARKS_MANAGER = 6; - // User opened the downloads manager + + /** User opened the downloads manager. */ public static final int ACTION_OPENED_DOWNLOADS_MANAGER = 7; - // User navigated to the webpage for a snippet shown on the NTP. + + /** User navigated to the webpage for a snippet shown on the NTP. */ public static final int ACTION_OPENED_SNIPPET = 8; - // User clicked on the "learn more" link in the footer. + + /** User clicked on the "learn more" link in the footer. */ public static final int ACTION_CLICKED_LEARN_MORE = 9; - // User clicked on the "Refresh" button in the "all dismissed" state. + + /** User clicked on the "Refresh" button in the "all dismissed" state. */ public static final int ACTION_CLICKED_ALL_DISMISSED_REFRESH = 10; - // The number of possible actions + + /** The number of possible actions. */ private static final int NUM_ACTIONS = 11; - // User navigated to a page using the omnibox. + /** User navigated to a page using the omnibox. */ private static final int RAPPOR_ACTION_NAVIGATED_USING_OMNIBOX = 0; - // User navigated to a page using one of the suggested tiles. + + /** User navigated to a page using one of the suggested tiles. */ public static final int RAPPOR_ACTION_VISITED_SUGGESTED_TILE = 1; - // Regular NTP impression (usually when a new tab is opened) + /** Regular NTP impression (usually when a new tab is opened). */ public static final int NTP_IMPRESSION_REGULAR = 0; - // Potential NTP impressions (instead of blank page if no tab is open) + /** Potential NTP impressions (instead of blank page if no tab is open). */ public static final int NTP_IMPESSION_POTENTIAL_NOTAB = 1; - // The number of possible NTP impression types + /** The number of possible NTP impression types */ private static final int NUM_NTP_IMPRESSION = 2; - /** Possible results when sizing the NewTabPageLayout. - * Do not remove or change existing values other than NUM_NTP_LAYOUT_RESULTS. */ + /** + * Possible results when sizing the NewTabPageLayout. + * Do not remove or change existing values other than NUM_NTP_LAYOUT_RESULTS. + */ @IntDef({NTP_LAYOUT_DOES_NOT_FIT, NTP_LAYOUT_FITS_WITHOUT_FIELD_TRIAL, - NTP_LAYOUT_FITS_WITH_FIELD_TRIAL, NUM_NTP_LAYOUT_RESULTS}) + NTP_LAYOUT_FITS_WITH_FIELD_TRIAL, NTP_LAYOUT_CONDENSED, NUM_NTP_LAYOUT_RESULTS}) @Retention(RetentionPolicy.SOURCE) public @interface NTPLayoutResult {} + /** The NewTabPageLayout does not fit above the fold and it is displayed as is. */ public static final int NTP_LAYOUT_DOES_NOT_FIT = 0; - /** The NewTabPageLayout does not fit above the fold, but we added some extra space so that - * Most Likely is cut off, indicating to the user they can scroll. */ + + /** + * The NewTabPageLayout does not fit above the fold, but we added some extra space so that + * Most Likely is cut off, indicating to the user they can scroll. + */ public static final int NTP_LAYOUT_DOES_NOT_FIT_PUSH_MOST_LIKELY = 1; + /** The NewTabPageLayout fits above the fold, the field trial is not enabled. */ public static final int NTP_LAYOUT_FITS_NO_FIELD_TRIAL = 2; - /** The NewTabPageLayout fits above the fold, but cannot allow space for the field trial - * experiment. */ + + /** + * The NewTabPageLayout fits above the fold, but cannot allow space for the field trial + * experiment. + */ public static final int NTP_LAYOUT_FITS_WITHOUT_FIELD_TRIAL = 3; + /** The NewTabPageLayout fits above the fold allowing space for the field trial experiment. */ public static final int NTP_LAYOUT_FITS_WITH_FIELD_TRIAL = 4; - /** The number of possible results for the NewTabPageLayout calculations. */ - public static final int NUM_NTP_LAYOUT_RESULTS = 5; - /** Possible results when updating content suggestions list in the UI. Keep in sync with the + /** The NewTabPageLayout is condensed to take up minimal space. */ + public static final int NTP_LAYOUT_CONDENSED = 5; + + /** The number of possible results for the NewTabPageLayout calculations. */ + public static final int NUM_NTP_LAYOUT_RESULTS = 6; + + /** + * Possible results when updating content suggestions list in the UI. Keep in sync with the * ContentSuggestionsUIUpdateResult enum in histograms.xml. Do not remove or change existing - * values other than NUM_UI_UPDATE_RESULTS. */ + * values other than NUM_UI_UPDATE_RESULTS. + */ @IntDef({UI_UPDATE_SUCCESS_APPENDED, UI_UPDATE_SUCCESS_REPLACED, UI_UPDATE_FAIL_ALL_SEEN, UI_UPDATE_FAIL_DISABLED}) @Retention(RetentionPolicy.SOURCE) public @interface ContentSuggestionsUIUpdateResult {} - /** The content suggestions are successfully appended (because they are set for the first time - * or explicitly marked to be appended). */ + + /** + * The content suggestions are successfully appended (because they are set for the first time + * or explicitly marked to be appended). + */ public static final int UI_UPDATE_SUCCESS_APPENDED = 0; - /** Update successful, suggestions were replaced (some of them possibly seen, the exact number - * reported in a separate histogram). */ + + /** + * Update successful, suggestions were replaced (some of them possibly seen, the exact number + * reported in a separate histogram). + */ public static final int UI_UPDATE_SUCCESS_REPLACED = 1; + /** Update failed, all previous content suggestions have been seen (and kept). */ public static final int UI_UPDATE_FAIL_ALL_SEEN = 2; + /** Update failed, because it is disabled by a variation parameter. */ public static final int UI_UPDATE_FAIL_DISABLED = 3; - public static final int NUM_UI_UPDATE_RESULTS = 4; - // The NTP was loaded in a cold startup. + private static final int NUM_UI_UPDATE_RESULTS = 4; + + /** The NTP was loaded in a cold startup. */ private static final int LOAD_TYPE_COLD_START = 0; - // The NTP was loaded in a warm startup. + + /** The NTP was loaded in a warm startup. */ private static final int LOAD_TYPE_WARM_START = 1; - // The NTP was loaded at some other time after activity creation and the user interacted with - // the activity in the meantime. + + /** + * The NTP was loaded at some other time after activity creation and the user interacted with + * the activity in the meantime. + */ private static final int LOAD_TYPE_OTHER = 2; - // The number of load types. + + /** The number of load types. */ private static final int LOAD_TYPE_COUNT = 3; /** @@ -223,7 +266,7 @@ } /** - * Records the type of load for the ntp, such as cold or warm start. + * Records the type of load for the NTP, such as cold or warm start. */ public static void recordLoadType(ChromeActivity activity) { if (activity.getLastUserInteractionTime() > 0) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java index 74839f2..f8f7d415 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -32,6 +32,7 @@ import org.chromium.base.VisibleForTesting; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ntp.LogoBridge.Logo; import org.chromium.chrome.browser.ntp.LogoBridge.LogoObserver; import org.chromium.chrome.browser.ntp.NewTabPage.DestructionObserver; @@ -43,6 +44,7 @@ import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate; import org.chromium.chrome.browser.suggestions.Tile; +import org.chromium.chrome.browser.suggestions.TileGridLayout; import org.chromium.chrome.browser.suggestions.TileGroup; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.util.MathUtils; @@ -72,8 +74,8 @@ private LogoView mSearchProviderLogoView; private View mSearchBoxView; private ImageView mVoiceSearchButton; - private MostVisitedLayout mMostVisitedLayout; - private View mMostVisitedPlaceholder; + private TileGridLayout mTileGridLayout; + private View mTileGridPlaceholder; private View mNoSearchLogoSpacer; private OnSearchBoxScrollListener mSearchBoxScrollListener; @@ -99,7 +101,7 @@ /** Flag used to request some layout changes after the next layout pass is completed. */ private boolean mTileCountChanged; - private boolean mSnapshotMostVisitedChanged; + private boolean mSnapshotTileGridChanged; private boolean mNewTabPageRecyclerViewChanged; private int mSnapshotWidth; private int mSnapshotHeight; @@ -212,9 +214,8 @@ } }); - mMostVisitedLayout = - (MostVisitedLayout) mNewTabPageLayout.findViewById(R.id.most_visited_layout); - mMostVisitedLayout.setMaxRows( + mTileGridLayout = (TileGridLayout) mNewTabPageLayout.findViewById(R.id.tile_grid_layout); + mTileGridLayout.setMaxRows( searchProviderHasLogo ? MAX_TILE_ROWS_WITH_LOGO : MAX_TILE_ROWS_WITHOUT_LOGO); mTileGroup = new TileGroup( mManager, mContextMenuManager, mTileGroupDelegate, /* observer = */ this); @@ -229,6 +230,9 @@ mNewTabPageLayout.addOnLayoutChangeListener(this); setSearchProviderHasLogo(searchProviderHasLogo); + mSearchProviderLogoView.setVisibility( + ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_CONDENSED_LAYOUT) ? View.GONE + : View.VISIBLE); mPendingLoadTasks++; mTileGroup.startObserving(MAX_TILES); @@ -472,7 +476,7 @@ if (logo == null && fromCache) return; mSearchProviderLogoView.setMananger(mManager); mSearchProviderLogoView.updateLogo(logo); - mSnapshotMostVisitedChanged = true; + mSnapshotTileGridChanged = true; } }); } @@ -488,26 +492,26 @@ // Set a bit more top padding if there is no logo. int paddingTop = getResources().getDimensionPixelSize(hasLogo - ? R.dimen.most_visited_layout_padding_top - : R.dimen.most_visited_layout_no_logo_padding_top); - mMostVisitedLayout.setPadding(0, paddingTop, 0, mMostVisitedLayout.getPaddingBottom()); + ? R.dimen.tile_grid_layout_padding_top + : R.dimen.tile_grid_layout_no_logo_padding_top); + mTileGridLayout.setPadding(0, paddingTop, 0, mTileGridLayout.getPaddingBottom()); // Hide or show all the views above the Most Visited items. int visibility = hasLogo ? View.VISIBLE : View.GONE; int childCount = mNewTabPageLayout.getChildCount(); for (int i = 0; i < childCount; i++) { View child = mNewTabPageLayout.getChildAt(i); - if (child == mMostVisitedLayout) break; + if (child == mTileGridLayout) break; // Don't change the visibility of a ViewStub as that will automagically inflate it. if (child instanceof ViewStub) continue; child.setVisibility(visibility); } - updateMostVisitedPlaceholderVisibility(); + updateTileGridPlaceholderVisibility(); onUrlFocusAnimationChanged(); - mSnapshotMostVisitedChanged = true; + mSnapshotTileGridChanged = true; } /** @@ -687,7 +691,7 @@ boolean shouldCaptureThumbnail() { if (getWidth() == 0 || getHeight() == 0) return false; - return mNewTabPageRecyclerViewChanged || mSnapshotMostVisitedChanged + return mNewTabPageRecyclerViewChanged || mSnapshotTileGridChanged || getWidth() != mSnapshotWidth || getHeight() != mSnapshotHeight || mRecyclerView.computeVerticalScrollOffset() != mSnapshotScrollY; } @@ -702,7 +706,7 @@ mSnapshotWidth = getWidth(); mSnapshotHeight = getHeight(); mSnapshotScrollY = mRecyclerView.computeVerticalScrollOffset(); - mSnapshotMostVisitedChanged = false; + mSnapshotTileGridChanged = false; mNewTabPageRecyclerViewChanged = false; } @@ -733,25 +737,25 @@ * Shows the most visited placeholder ("Nothing to see here") if there are no most visited * items and there is no search provider logo. */ - private void updateMostVisitedPlaceholderVisibility() { + private void updateTileGridPlaceholderVisibility() { boolean showPlaceholder = mTileGroup.hasReceivedData() - && mMostVisitedLayout.getChildCount() == 0 && !mSearchProviderHasLogo; + && mTileGridLayout.getChildCount() == 0 && !mSearchProviderHasLogo; mNoSearchLogoSpacer.setVisibility( (mSearchProviderHasLogo || showPlaceholder) ? View.GONE : View.INVISIBLE); if (showPlaceholder) { - if (mMostVisitedPlaceholder == null) { - ViewStub mostVisitedPlaceholderStub = (ViewStub) mNewTabPageLayout - .findViewById(R.id.most_visited_placeholder_stub); + if (mTileGridPlaceholder == null) { + ViewStub placeholderStub = + (ViewStub) mNewTabPageLayout.findViewById(R.id.tile_grid_placeholder_stub); - mMostVisitedPlaceholder = mostVisitedPlaceholderStub.inflate(); + mTileGridPlaceholder = placeholderStub.inflate(); } - mMostVisitedLayout.setVisibility(GONE); - mMostVisitedPlaceholder.setVisibility(VISIBLE); - } else if (mMostVisitedPlaceholder != null) { - mMostVisitedLayout.setVisibility(VISIBLE); - mMostVisitedPlaceholder.setVisibility(GONE); + mTileGridLayout.setVisibility(GONE); + mTileGridPlaceholder.setVisibility(VISIBLE); + } else if (mTileGridPlaceholder != null) { + mTileGridLayout.setVisibility(VISIBLE); + mTileGridPlaceholder.setVisibility(GONE); } } @@ -805,8 +809,8 @@ @Override public void onTileDataChanged() { - mTileGroup.renderTileViews(mMostVisitedLayout, !mLoadHasCompleted); - mSnapshotMostVisitedChanged = true; + mTileGroup.renderTileViews(mTileGridLayout, !mLoadHasCompleted); + mSnapshotTileGridChanged = true; } @Override @@ -814,13 +818,13 @@ // If the number of tile rows change while the URL bar is focused, the icons' // position will be wrong. Schedule the translation to be updated. if (mUrlFocusChangePercent == 1f) mTileCountChanged = true; - updateMostVisitedPlaceholderVisibility(); + updateTileGridPlaceholderVisibility(); } @Override public void onTileIconChanged(Tile tile) { - mMostVisitedLayout.updateIconView(tile.getUrl(), tile.getIcon()); - mSnapshotMostVisitedChanged = true; + mTileGridLayout.updateIconView(tile); + mSnapshotTileGridChanged = true; } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java index 3d6cef1..aad8ce4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
@@ -12,6 +12,7 @@ import org.chromium.base.Callback; import org.chromium.base.VisibleForTesting; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ntp.ContextMenuManager; import org.chromium.chrome.browser.ntp.cards.NewTabPageViewHolder.PartialBindCallback; import org.chromium.chrome.browser.ntp.snippets.SectionHeaderViewHolder; @@ -87,7 +88,8 @@ mRoot.addChild(new TileGrid(uiDelegate, mContextMenuManager, tileGroupDelegate)); } mRoot.addChildren(mSections, mSigninPromo, mAllDismissed, mFooter); - if (mAboveTheFoldView == null) { + if (mAboveTheFoldView == null + || ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_CONDENSED_LAYOUT)) { mBottomSpacer = null; } else { mBottomSpacer = new SpacingItem();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java index d3ff538..5639eb2f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java
@@ -30,6 +30,7 @@ import org.chromium.base.Log; import org.chromium.chrome.R; import org.chromium.chrome.R.string; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ntp.ContextMenuManager.TouchDisableableView; import org.chromium.chrome.browser.ntp.NewTabPageLayout; import org.chromium.chrome.browser.ntp.snippets.SectionHeaderViewHolder; @@ -327,7 +328,8 @@ // Peeking is disabled in the card offset field trial and the increased visibility feature. if (CardsVariationParameters.getFirstCardOffsetDp() != 0 - || SnippetsConfig.isIncreasedCardVisibilityEnabled()) { + || SnippetsConfig.isIncreasedCardVisibilityEnabled() + || ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_CONDENSED_LAYOUT)) { peekingCard.updatePeek(0, /* shouldAnimate */ false); return; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/ExponentialBackoffScheduler.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/ExponentialBackoffScheduler.java index 1515888..e9a6ef54 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/ExponentialBackoffScheduler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/ExponentialBackoffScheduler.java
@@ -34,8 +34,6 @@ * * This class is not thread-safe because any two different classes could be accessing the same * SharedPreferences. - * - * TODO(dfalcantara): Consider making this an AlarmManagerHelper class to manage general alarms. */ @NotThreadSafe public class ExponentialBackoffScheduler {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaClient.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaClient.java index 98b8f87..d3e0bd6b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaClient.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaClient.java
@@ -4,27 +4,23 @@ package org.chromium.chrome.browser.omaha; -import android.app.AlarmManager; import android.app.IntentService; -import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.content.pm.ApplicationInfo; import android.os.Build; -import android.os.Looper; +import android.support.annotation.IntDef; -import org.chromium.base.ApiCompatibilityUtils; -import org.chromium.base.ApplicationStatus; import org.chromium.base.Log; +import org.chromium.base.ThreadUtils; import org.chromium.base.VisibleForTesting; -import org.chromium.chrome.browser.ChromeApplication; import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; -import java.util.UUID; import java.util.concurrent.TimeUnit; /** @@ -55,6 +51,9 @@ */ public class OmahaClient extends IntentService { // Results of {@link #handlePostRequest()}. + @Retention(RetentionPolicy.SOURCE) + @IntDef({POST_RESULT_NO_REQUEST, POST_RESULT_SENT, POST_RESULT_FAILED, POST_RESULT_SCHEDULED}) + @interface PostResult {} static final int POST_RESULT_NO_REQUEST = 0; static final int POST_RESULT_SENT = 1; static final int POST_RESULT_FAILED = 2; @@ -62,19 +61,15 @@ private static final String TAG = "omaha"; - // Intent actions. - private static final String ACTION_INITIALIZE = - "org.chromium.chrome.browser.omaha.ACTION_INITIALIZE"; + /** Deprecated; kept around to cancel alarms set for OmahaClient pre-M58. */ private static final String ACTION_REGISTER_REQUEST = "org.chromium.chrome.browser.omaha.ACTION_REGISTER_REQUEST"; - private static final String ACTION_POST_REQUEST = - "org.chromium.chrome.browser.omaha.ACTION_POST_REQUEST"; // Delays between events. - private static final long MS_POST_BASE_DELAY = TimeUnit.HOURS.toMillis(1); - private static final long MS_POST_MAX_DELAY = TimeUnit.HOURS.toMillis(5); + static final long MS_POST_BASE_DELAY = TimeUnit.HOURS.toMillis(1); + static final long MS_POST_MAX_DELAY = TimeUnit.HOURS.toMillis(5); static final long MS_BETWEEN_REQUESTS = TimeUnit.HOURS.toMillis(5); - private static final int MS_CONNECTION_TIMEOUT = (int) TimeUnit.MINUTES.toMillis(1); + static final int MS_CONNECTION_TIMEOUT = (int) TimeUnit.MINUTES.toMillis(1); // Strings indicating how the Chrome APK arrived on the user's device. These values MUST NOT // be changed without updating the corresponding Omaha server strings. @@ -87,8 +82,7 @@ // Member fields not persisted to disk. private boolean mStateHasBeenRestored; - private ExponentialBackoffScheduler mBackoffScheduler; - private RequestGenerator mGenerator; + private OmahaDelegate mDelegate; // State saved written to and read from disk. private RequestData mCurrentRequest; @@ -105,176 +99,115 @@ setIntentRedelivery(true); } - @VisibleForTesting - long getTimestampForNextPostAttempt() { - return mTimestampForNextPostAttempt; - } - - @VisibleForTesting - long getTimestampForNewRequest() { - return mTimestampForNewRequest; - } - - @VisibleForTesting - int getCumulativeFailedAttempts() { - return getBackoffScheduler().getNumFailedAttempts(); - } - - /** - * Creates the scheduler used to space out POST attempts. - */ - @VisibleForTesting - ExponentialBackoffScheduler createBackoffScheduler(String prefPackage, Context context, - long base, long max) { - return new ExponentialBackoffScheduler(prefPackage, context, base, max); - } - - /** - * Creates the request generator used to create Omaha XML. - */ - @VisibleForTesting - RequestGenerator createRequestGenerator(Context context) { - return ((ChromeApplication) context.getApplicationContext()).createOmahaRequestGenerator(); - } - /** * Handles an action on a thread separate from the UI thread. * @param intent Intent fired by some part of Chrome. */ @Override public void onHandleIntent(Intent intent) { - assert Looper.myLooper() != Looper.getMainLooper(); + assert !ThreadUtils.runningOnUiThread(); + run(); + } + protected void run() { if (OmahaBase.isDisabled() || Build.VERSION.SDK_INT > Build.VERSION_CODES.N || getRequestGenerator() == null) { Log.v(TAG, "Disabled. Ignoring intent."); return; } - restoreState(this); + if (mDelegate == null) mDelegate = new OmahaDelegateImpl(this); - if (ACTION_INITIALIZE.equals(intent.getAction())) { - handleInitialize(); - } else if (ACTION_REGISTER_REQUEST.equals(intent.getAction())) { - handleRegisterRequest(); - } else if (ACTION_POST_REQUEST.equals(intent.getAction())) { - handlePostRequest(); - } else { - Log.e(TAG, "Got unknown action from intent: " + intent.getAction()); + restoreState(getContext()); + + long nextTimestamp = Long.MAX_VALUE; + if (mDelegate.isChromeBeingUsed()) { + handleRegisterActiveRequest(); + nextTimestamp = Math.min(nextTimestamp, mTimestampForNewRequest); } - saveState(this); + if (hasRequest()) { + int result = handlePostRequest(); + if (result == POST_RESULT_FAILED || result == POST_RESULT_SCHEDULED) { + nextTimestamp = Math.min(nextTimestamp, mTimestampForNextPostAttempt); + } + } + + // TODO(dfalcantara): Prevent Omaha code from repeatedly rescheduling itself immediately in + // case a scheduling error occurs. + if (nextTimestamp != Long.MAX_VALUE && nextTimestamp >= 0) { + mDelegate.scheduleService(this, nextTimestamp); + } + saveState(getContext()); } /** * Begin communicating with the Omaha Update Server. */ static void startService(Context context) { - Intent omahaIntent = createInitializeIntent(context); - context.startService(omahaIntent); + context.startService(createOmahaIntent(context)); } - static Intent createInitializeIntent(Context context) { - Intent intent = new Intent(context, OmahaClient.class); - intent.setAction(ACTION_INITIALIZE); - return intent; - } - - /** - * Start a recurring alarm to fire request generation intents. - */ - private void handleInitialize() { - scheduleActiveUserCheck(); - - // If a request exists, kick off POSTing it to the server immediately. - if (hasRequest()) handlePostRequest(); - } - - /** - * Returns an Intent for registering a new request to send to the server. - */ - static Intent createRegisterRequestIntent(Context context) { - Intent intent = new Intent(context, OmahaClient.class); - intent.setAction(ACTION_REGISTER_REQUEST); - return intent; + static Intent createOmahaIntent(Context context) { + return new Intent(context, OmahaClient.class); } /** * Determines if a new request should be generated. New requests are only generated if enough * time has passed between now and the last time a request was generated. */ - private void handleRegisterRequest() { - if (!isChromeBeingUsed()) { - getBackoffScheduler().cancelAlarm(createRegisterRequestIntent(this)); - return; - } - + private void handleRegisterActiveRequest() { // If the current request is too old, generate a new one. long currentTimestamp = getBackoffScheduler().getCurrentTime(); boolean isTooOld = hasRequest() && mCurrentRequest.getAgeInMilliseconds(currentTimestamp) >= MS_BETWEEN_REQUESTS; - boolean isOverdue = !hasRequest() && currentTimestamp >= mTimestampForNewRequest; + boolean isOverdue = currentTimestamp >= mTimestampForNewRequest; if (isTooOld || isOverdue) { registerNewRequest(currentTimestamp); } - - // Send the request. - if (hasRequest()) { - handlePostRequest(); - } - } - - /** - * Returns an Intent for POSTing the current request to the Omaha server. - */ - static Intent createPostRequestIntent(Context context) { - Intent intent = new Intent(context, OmahaClient.class); - intent.setAction(ACTION_POST_REQUEST); - return intent; } /** * Sends the request it is holding. */ - @VisibleForTesting - protected int handlePostRequest() { - if (!hasRequest()) return POST_RESULT_NO_REQUEST; + private int handlePostRequest() { + if (!hasRequest()) { + mDelegate.onHandlePostRequestDone(POST_RESULT_NO_REQUEST, false); + return POST_RESULT_NO_REQUEST; + } // If enough time has passed since the last attempt, try sending a request. int result; long currentTimestamp = getBackoffScheduler().getCurrentTime(); + boolean installEventWasSent = false; if (currentTimestamp >= mTimestampForNextPostAttempt) { // All requests made during the same session should have the same ID. - String sessionID = generateRandomUUID(); + String sessionID = mDelegate.generateUUID(); boolean sendingInstallRequest = mSendInstallEvent; boolean succeeded = generateAndPostRequest(currentTimestamp, sessionID); if (succeeded && sendingInstallRequest) { // Only the first request ever generated should contain an install event. mSendInstallEvent = false; + installEventWasSent = true; // Create and immediately send another request for a ping and update check. registerNewRequest(currentTimestamp); - generateAndPostRequest(currentTimestamp, sessionID); + succeeded &= generateAndPostRequest(currentTimestamp, sessionID); } result = succeeded ? POST_RESULT_SENT : POST_RESULT_FAILED; } else { - schedulePost(); result = POST_RESULT_SCHEDULED; } + mDelegate.onHandlePostRequestDone(result, installEventWasSent); return result; } - /** Set an alarm to POST at the proper time. Previous alarms are destroyed. */ - private void schedulePost() { - Intent postIntent = createPostRequestIntent(this); - getBackoffScheduler().createAlarm(postIntent, mTimestampForNextPostAttempt); - } - private boolean generateAndPostRequest(long currentTimestamp, String sessionID) { ExponentialBackoffScheduler scheduler = getBackoffScheduler(); + boolean succeeded = false; try { // Generate the XML for the current request. long installAgeInDays = RequestGenerator.installAge(currentTimestamp, @@ -295,61 +228,29 @@ mLatestVersion = parser.getNewVersion(); mMarketURL = parser.getURL(); + succeeded = true; + } catch (RequestFailureException e) { + Log.e(TAG, "Failed to contact server: ", e); + } + + if (succeeded) { // If we've gotten this far, we've successfully sent a request. mCurrentRequest = null; - mTimestampForNewRequest = getBackoffScheduler().getCurrentTime() + MS_BETWEEN_REQUESTS; - scheduleActiveUserCheck(); - scheduler.resetFailedAttempts(); + mTimestampForNewRequest = scheduler.getCurrentTime() + MS_BETWEEN_REQUESTS; mTimestampForNextPostAttempt = scheduler.calculateNextTimestamp(); Log.i(TAG, "Request to Server Successful. Timestamp for next request:" + String.valueOf(mTimestampForNextPostAttempt)); - - return true; - } catch (RequestFailureException e) { - // Set the alarm to try again later. - Log.e(TAG, "Failed to contact server: ", e); - scheduler.increaseFailedAttempts(); + } else { + // Set the alarm to try again later. Failures are incremented after setting the timer + // to allow the first failure to incur the minimum base delay between POSTs. mTimestampForNextPostAttempt = scheduler.calculateNextTimestamp(); - scheduler.createAlarm(createPostRequestIntent(this), mTimestampForNextPostAttempt); - return false; + scheduler.increaseFailedAttempts(); } - } - /** - * Sets a repeating alarm that fires request registration Intents. - * Setting the alarm overwrites whatever alarm is already there, and rebooting - * clears whatever alarms are currently set. - */ - private void scheduleActiveUserCheck() { - Intent registerIntent = createRegisterRequestIntent(this); - PendingIntent pIntent = PendingIntent.getService(this, 0, registerIntent, 0); - AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE); - setAlarm(am, pIntent, mTimestampForNewRequest); - } - - /** - * Sets up a timer to fire after each interval. - * Override to prevent a real alarm from being set. - */ - @VisibleForTesting - protected void setAlarm(AlarmManager am, PendingIntent operation, long triggerAtTime) { - try { - am.setRepeating(AlarmManager.RTC, triggerAtTime, MS_BETWEEN_REQUESTS, operation); - } catch (SecurityException e) { - Log.e(TAG, "Failed to set repeating alarm."); - } - } - - /** - * Determine whether or not Chrome is currently being used actively. - */ - @VisibleForTesting - protected boolean isChromeBeingUsed() { - boolean isChromeVisible = ApplicationStatus.hasVisibleActivities(); - boolean isScreenOn = ApiCompatibilityUtils.isInteractive(this); - return isChromeVisible && isScreenOn; + mDelegate.onGenerateAndPostRequestDone(succeeded); + return succeeded; } /** @@ -357,8 +258,7 @@ * fresh. * @param currentTimestamp Current time. */ - @VisibleForTesting - void registerNewRequest(long currentTimestamp) { + private void registerNewRequest(long currentTimestamp) { mCurrentRequest = createRequestData(currentTimestamp, null); getBackoffScheduler().resetFailedAttempts(); mTimestampForNextPostAttempt = currentTimestamp; @@ -366,22 +266,22 @@ // Tentatively set the timestamp for a new request. This will be updated when the server // is successfully contacted. mTimestampForNewRequest = currentTimestamp + MS_BETWEEN_REQUESTS; - scheduleActiveUserCheck(); + + mDelegate.onRegisterNewRequestDone(mTimestampForNewRequest, mTimestampForNextPostAttempt); } private RequestData createRequestData(long currentTimestamp, String persistedID) { // If we're sending a persisted event, keep trying to send the same request ID. String requestID; if (persistedID == null || INVALID_REQUEST_ID.equals(persistedID)) { - requestID = generateRandomUUID(); + requestID = mDelegate.generateUUID(); } else { requestID = persistedID; } return new RequestData(mSendInstallEvent, currentTimestamp, requestID, mInstallSource); } - @VisibleForTesting - boolean hasRequest() { + private boolean hasRequest() { return mCurrentRequest != null; } @@ -390,8 +290,7 @@ * @return the XML response as a String. * @throws RequestFailureException if the request fails. */ - @VisibleForTesting - String postRequest(long timestamp, String xml) throws RequestFailureException { + private String postRequest(long timestamp, String xml) throws RequestFailureException { String response = null; HttpURLConnection urlConnection = null; @@ -401,7 +300,7 @@ // Prepare the HTTP header. urlConnection.setDoOutput(true); urlConnection.setFixedLengthStreamingMode(xml.getBytes().length); - if (mSendInstallEvent && getCumulativeFailedAttempts() > 0) { + if (mSendInstallEvent && getBackoffScheduler().getNumFailedAttempts() > 0) { String age = Long.toString(mCurrentRequest.getAgeInSeconds(timestamp)); urlConnection.addRequestProperty("X-RequestAge", age); } @@ -441,33 +340,17 @@ } /** - * Determine how the Chrome APK arrived on the device. - * @param context Context to pull resources from. - * @return A String indicating the install source. - */ - String determineInstallSource() { - boolean isInSystemImage = (getApplicationFlags() & ApplicationInfo.FLAG_SYSTEM) != 0; - return isInSystemImage ? INSTALL_SOURCE_SYSTEM : INSTALL_SOURCE_ORGANIC; - } - - /** - * Returns the Application's flags, used to determine if Chrome was installed as part of the - * system image. - * @return The Application's flags. - */ - @VisibleForTesting - int getApplicationFlags() { - return getApplicationInfo().flags; - } - - /** * Reads the data back from the file it was saved to. Uses SharedPreferences to handle I/O. * Sanity checks are performed on the timestamps to guard against clock changing. */ @VisibleForTesting void restoreState(Context context) { if (mStateHasBeenRestored) return; - long currentTime = getBackoffScheduler().getCurrentTime(); + + String installSource = + mDelegate.isInSystemImage() ? INSTALL_SOURCE_SYSTEM : INSTALL_SOURCE_ORGANIC; + ExponentialBackoffScheduler scheduler = getBackoffScheduler(); + long currentTime = scheduler.getCurrentTime(); SharedPreferences preferences = OmahaBase.getSharedPreferences(context); mTimestampForNewRequest = @@ -476,8 +359,7 @@ preferences.getLong(OmahaBase.PREF_TIMESTAMP_FOR_NEXT_POST_ATTEMPT, currentTime); mTimestampOfInstall = preferences.getLong(OmahaBase.PREF_TIMESTAMP_OF_INSTALL, currentTime); mSendInstallEvent = preferences.getBoolean(OmahaBase.PREF_SEND_INSTALL_EVENT, true); - mInstallSource = - preferences.getString(OmahaBase.PREF_INSTALL_SOURCE, determineInstallSource()); + mInstallSource = preferences.getString(OmahaBase.PREF_INSTALL_SOURCE, installSource); mLatestVersion = preferences.getString(OmahaBase.PREF_LATEST_VERSION, ""); mMarketURL = preferences.getString(OmahaBase.PREF_MARKET_URL, ""); @@ -501,13 +383,15 @@ // Confirm that the timestamp for the next POST is less than the current delay. long delayToNextPost = mTimestampForNextPostAttempt - currentTime; - if (delayToNextPost > getBackoffScheduler().getGeneratedDelay()) { + long lastGeneratedDelay = scheduler.getGeneratedDelay(); + if (delayToNextPost > lastGeneratedDelay) { Log.w(TAG, "Delay to next post attempt (" + delayToNextPost - + ") is greater than expected (" + getBackoffScheduler().getGeneratedDelay() + + ") is greater than expected (" + lastGeneratedDelay + "). Resetting to now."); mTimestampForNextPostAttempt = currentTime; } + migrateToNewerChromeVersions(); mStateHasBeenRestored = true; } @@ -531,26 +415,32 @@ editor.putString(OmahaBase.PREF_MARKET_URL, mMarketURL == null ? "" : mMarketURL); editor.putString(OmahaBase.PREF_INSTALL_SOURCE, mInstallSource); editor.apply(); + + mDelegate.onSaveStateDone(mTimestampForNewRequest, mTimestampForNextPostAttempt); } - /** - * Generates a random UUID. - */ - @VisibleForTesting - protected String generateRandomUUID() { - return UUID.randomUUID().toString(); + private void migrateToNewerChromeVersions() { + // Remove any repeating alarms in favor of the new scheduling setup on M58 and up. + // Seems cheaper to cancel the alarm repeatedly than to store a SharedPreference and never + // do it again. + Intent intent = new Intent(getContext(), OmahaClient.class); + intent.setAction(ACTION_REGISTER_REQUEST); + getBackoffScheduler().cancelAlarm(intent); } - protected final RequestGenerator getRequestGenerator() { - if (mGenerator == null) mGenerator = createRequestGenerator(this); - return mGenerator; + Context getContext() { + return mDelegate.getContext(); } - protected final ExponentialBackoffScheduler getBackoffScheduler() { - if (mBackoffScheduler == null) { - mBackoffScheduler = createBackoffScheduler( - OmahaBase.PREF_PACKAGE, this, MS_POST_BASE_DELAY, MS_POST_MAX_DELAY); - } - return mBackoffScheduler; + private RequestGenerator getRequestGenerator() { + return mDelegate.getRequestGenerator(); + } + + private ExponentialBackoffScheduler getBackoffScheduler() { + return mDelegate.getScheduler(); + } + + void setDelegateForTests(OmahaDelegate delegate) { + mDelegate = delegate; } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaDelegate.java new file mode 100644 index 0000000..9509174 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaDelegate.java
@@ -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. + +package org.chromium.chrome.browser.omaha; + +import android.app.Service; +import android.content.Context; + +import org.chromium.chrome.browser.omaha.OmahaClient.PostResult; + +/** Delegates calls out from the OmahaClient. */ +public abstract class OmahaDelegate { + protected final Context mContext; + private RequestGenerator mRequestGenerator; + + OmahaDelegate(Context context) { + mContext = context; + } + + /** @return Context that is used to interact with the system. */ + Context getContext() { + return mContext; + } + + /** @return Whether Chrome is installed as part of the system image. */ + abstract boolean isInSystemImage(); + + /** @return The scheduler used to trigger jobs. */ + abstract ExponentialBackoffScheduler getScheduler(); + + /** @return The {@link RequestGenerator} used to create Omaha XML. */ + final RequestGenerator getRequestGenerator() { + if (mRequestGenerator == null) mRequestGenerator = createRequestGenerator(getContext()); + return mRequestGenerator; + } + + /** @return A UUID that can be used to identify particular requests. */ + abstract String generateUUID(); + + /** Determine whether or not Chrome is currently being used actively. */ + abstract boolean isChromeBeingUsed(); + + /** + * Schedules the {@link Service} to run again at the given time. + * @param service Service that is doing the scheduling. + * @param nextTimestampMs When the service should be run again. + */ + abstract void scheduleService(Service service, long nextTimestampMs); + + /** Creates a {@link RequestGenerator}. */ + abstract RequestGenerator createRequestGenerator(Context context); + + /** + * Called when {@link OmahaClient#registerNewRequest} finishes. + * @param timestampRequestMs When the next active user request should be generated. + * @param timestampPostMs Earliest time the next POST should be allowed. + */ + void onRegisterNewRequestDone(long timestampRequestMs, long timestampPostMs) {} + + /** + * Called when {@link OmahaClient#handlePostRequest} finishes. + * @param result See {@link PostResult}. + * @param installEventWasSent Whether or not an install event was sent. + */ + void onHandlePostRequestDone(@PostResult int result, boolean installEventWasSent) {} + + /** + * Called when {@link OmahaClient#generateAndPostRequest} finishes. + * @param succeeded Whether or not the post was successfully received by the server. + */ + void onGenerateAndPostRequestDone(boolean succeeded) {} + + /** + * Called when {@link OmahaClient#saveState} finishes. + * @param timestampRequestMs When the next active user request should be generated. + * @param timestampPostMs Earliest time the next POST should be allowed. + */ + void onSaveStateDone(long timestampRequestMs, long timestampPostMs) {} +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaDelegateImpl.java new file mode 100644 index 0000000..b0ae437 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaDelegateImpl.java
@@ -0,0 +1,62 @@ +// 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. + +package org.chromium.chrome.browser.omaha; + +import android.app.Service; +import android.content.Context; +import android.content.pm.ApplicationInfo; + +import org.chromium.base.ApiCompatibilityUtils; +import org.chromium.base.ApplicationStatus; +import org.chromium.chrome.browser.ChromeApplication; + +import java.util.UUID; + +/** Delegates calls out from the OmahaClient. */ +public class OmahaDelegateImpl extends OmahaDelegate { + private final ExponentialBackoffScheduler mScheduler; + + OmahaDelegateImpl(Context context) { + super(context); + mScheduler = new ExponentialBackoffScheduler(OmahaBase.PREF_PACKAGE, context, + OmahaClient.MS_POST_BASE_DELAY, OmahaClient.MS_POST_MAX_DELAY); + } + + @Override + boolean isInSystemImage() { + return (getContext().getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) != 0; + } + + @Override + ExponentialBackoffScheduler getScheduler() { + return mScheduler; + } + + @Override + String generateUUID() { + return UUID.randomUUID().toString(); + } + + @Override + boolean isChromeBeingUsed() { + boolean isChromeVisible = ApplicationStatus.hasVisibleActivities(); + boolean isScreenOn = ApiCompatibilityUtils.isInteractive(getContext()); + return isChromeVisible && isScreenOn; + } + + @Override + void scheduleService(Service service, long nextTimestamp) { + if (service instanceof OmahaClient) { + getScheduler().createAlarm(OmahaClient.createOmahaIntent(getContext()), nextTimestamp); + } else { + // TODO(dfalcantara): Do something here with a JobService. + } + } + + @Override + protected RequestGenerator createRequestGenerator(Context context) { + return ((ChromeApplication) context.getApplicationContext()).createOmahaRequestGenerator(); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java index 95a967e..0e125b27 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -559,7 +559,9 @@ int decorHeight = getWindowDelegate().getDecorViewHeight(); int availableViewportHeight = Math.min(mTempRect.height(), decorHeight); int availableListHeight = availableViewportHeight - anchorBottomRelativeToContent; - int desiredHeight = Math.min(availableListHeight, getIdealHeight()); + // If the bottom sheet is used, the suggestions should consume all available space. + int desiredHeight = mBottomSheet != null + ? availableListHeight : Math.min(availableListHeight, getIdealHeight()); if (layoutParams.height != desiredHeight) { layoutParams.height = desiredHeight; updateLayout = true; @@ -2248,11 +2250,14 @@ } /** - * Update the fading background view that shows when the omnibox is focused. + * Update the fading background view that shows when the omnibox is focused. If Chrome Home is + * enabled, this method is a no-op. * @param visible Whether the background should be made visible. */ private void updateFadingBackgroundView(boolean visible) { - if (getToolbarDataProvider() == null) return; + // If Chrome Home is enabled (the bottom sheet is not null), it will be controlling the + // fading view, so block any initialization and updating here. + if (getToolbarDataProvider() == null || mBottomSheet != null) return; if (mFadingView == null) initFadingOverlayView();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFactory.java index 335d160..9eaf457 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFactory.java
@@ -13,6 +13,7 @@ import android.util.Pair; import org.chromium.base.ContextUtils; +import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.UrlConstants; import org.chromium.chrome.browser.payments.PaymentAppFactory.PaymentAppCreatedCallback; import org.chromium.chrome.browser.payments.PaymentAppFactory.PaymentAppFactoryAddition; @@ -38,8 +39,14 @@ private static final String BASIC_CARD_PAYMENT_METHOD = "basic-card"; @Override - public void create(Context context, WebContents webContents, Set<String> methods, + public void create(WebContents webContents, Set<String> methods, PaymentAppCreatedCallback callback) { + Context context = ChromeActivity.fromWebContents(webContents); + if (context == null) { + callback.onAllPaymentAppsCreated(); + return; + } + Map<String, AndroidPaymentApp> installedApps = new HashMap<>(); PackageManager pm = context.getPackageManager(); Intent payIntent = new Intent(); @@ -114,7 +121,7 @@ for (ResolveInfo match : matches) { Pair<String, Drawable> appInfo = - new Pair<String, Drawable>(match.loadLabel(pm).toString(), match.loadIcon(pm)); + new Pair<>(match.loadLabel(pm).toString(), match.loadIcon(pm)); paymentAppsInfo.put(match.activityInfo.packageName, appInfo); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java index d097327..a23872b3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java
@@ -4,7 +4,6 @@ package org.chromium.chrome.browser.payments; -import android.content.Context; import android.os.Handler; import android.text.TextUtils; @@ -29,17 +28,14 @@ /** The method name for any type of credit card. */ public static final String BASIC_CARD_METHOD_NAME = "basic-card"; - private final Context mContext; private final WebContents mWebContents; /** * Builds a payment app backed by autofill cards. * - * @param context The context. * @param webContents The web contents where PaymentRequest was invoked. */ - public AutofillPaymentApp(Context context, WebContents webContents) { - mContext = context; + public AutofillPaymentApp(WebContents webContents) { mWebContents = webContents; } @@ -75,8 +71,8 @@ } if (methodName != null) { - instruments.add(new AutofillPaymentInstrument(mContext, mWebContents, card, - billingAddress, methodName)); + instruments.add(new AutofillPaymentInstrument( + mWebContents, card, billingAddress, methodName)); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java index 22294230..b781280 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java
@@ -11,6 +11,7 @@ import org.chromium.base.ApiCompatibilityUtils; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.autofill.PersonalDataManager; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; @@ -35,7 +36,6 @@ */ public class AutofillPaymentInstrument extends PaymentInstrument implements FullCardRequestDelegate, NormalizedAddressRequestDelegate { - private final Context mContext; private final WebContents mWebContents; private CreditCard mCard; private String mSecurityCode; @@ -49,26 +49,29 @@ /** * Builds a payment instrument for the given credit card. * - * @param context The application context. * @param webContents The web contents where PaymentRequest was invoked. * @param card The autofill card that can be used for payment. * @param billingAddress The billing address for the card. * @param methodName The payment method name, e.g., "basic-card", "visa", amex", or null. */ - public AutofillPaymentInstrument(Context context, WebContents webContents, CreditCard card, + public AutofillPaymentInstrument(WebContents webContents, CreditCard card, @Nullable AutofillProfile billingAddress, @Nullable String methodName) { - super(card.getGUID(), card.getObfuscatedNumber(), card.getName(), - card.getIssuerIconDrawableId() == 0 - ? null - : ApiCompatibilityUtils.getDrawable( - context.getResources(), card.getIssuerIconDrawableId())); - mContext = context; + super(card.getGUID(), card.getObfuscatedNumber(), card.getName(), null); mWebContents = webContents; mCard = card; mBillingAddress = billingAddress; mIsEditable = true; mMethodName = methodName; - checkAndUpateCardCompleteness(); + + Context context = ChromeActivity.fromWebContents(mWebContents); + if (context == null) return; + + if (card.getIssuerIconDrawableId() != 0) { + updateDrawableIcon(ApiCompatibilityUtils.getDrawable( + context.getResources(), card.getIssuerIconDrawableId())); + } + + checkAndUpateCardCompleteness(context); } @Override @@ -258,10 +261,14 @@ mCard = card; mMethodName = methodName; mBillingAddress = billingAddress; + + Context context = ChromeActivity.fromWebContents(mWebContents); + if (context == null) return; + updateIdentifierLabelsAndIcon(card.getGUID(), card.getObfuscatedNumber(), card.getName(), null, ApiCompatibilityUtils.getDrawable( - mContext.getResources(), card.getIssuerIconDrawableId())); - checkAndUpateCardCompleteness(); + context.getResources(), card.getIssuerIconDrawableId())); + checkAndUpateCardCompleteness(context); assert mIsComplete; assert mHasValidNumberAndName; } @@ -282,7 +289,7 @@ * Does not check that the card type is accepted by the merchant. This is done elsewhere to * filter out such cards from view entirely. */ - private void checkAndUpateCardCompleteness() { + private void checkAndUpateCardCompleteness(Context context) { int editMessageResId = 0; // Zero is the invalid resource Id. int editTitleResId = R.string.payments_edit_card; int invalidFieldsCount = 0; @@ -317,8 +324,8 @@ editTitleResId = R.string.payments_add_more_information; } - mEditMessage = editMessageResId == 0 ? null : mContext.getString(editMessageResId); - mEditTitle = mContext.getString(editTitleResId); + mEditMessage = editMessageResId == 0 ? null : context.getString(editMessageResId); + mEditTitle = context.getString(editTitleResId); mIsComplete = mEditMessage == null; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java index dbc2c624..9b76320 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java
@@ -344,7 +344,7 @@ // Ensure that |instrument| and |card| are never null. final AutofillPaymentInstrument instrument = isNewCard - ? new AutofillPaymentInstrument(mContext, mWebContents, new CreditCard(), + ? new AutofillPaymentInstrument(mWebContents, new CreditCard(), null /* billingAddress */, null /* methodName */) : toEdit; final CreditCard card = instrument.getCard();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentAppFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentAppFactory.java index dd8af08f..25fd9c1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentAppFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentAppFactory.java
@@ -4,8 +4,6 @@ package org.chromium.chrome.browser.payments; -import android.content.Context; - import org.chromium.base.VisibleForTesting; import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.content_public.browser.WebContents; @@ -50,13 +48,12 @@ /** * Builds instances of payment apps. * - * @param context The application context. * @param webContents The web contents that invoked PaymentRequest. * @param methods The methods that the merchant supports. * @param callback The callback to invoke when apps are created. */ - void create(Context context, WebContents webContents, Set<String> methods, - PaymentAppCreatedCallback callback); + void create( + WebContents webContents, Set<String> methods, PaymentAppCreatedCallback callback); } private PaymentAppFactory() { @@ -92,14 +89,13 @@ /** * Builds instances of payment apps. * - * @param context The context. * @param webContents The web contents where PaymentRequest was invoked. * @param methods The methods that the merchant supports. * @param callback The callback to invoke when apps are created. */ - public void create(Context context, WebContents webContents, Set<String> methods, + public void create(WebContents webContents, Set<String> methods, final PaymentAppCreatedCallback callback) { - callback.onPaymentAppCreated(new AutofillPaymentApp(context, webContents)); + callback.onPaymentAppCreated(new AutofillPaymentApp(webContents)); if (mAdditionalFactories.isEmpty()) { callback.onAllPaymentAppsCreated(); @@ -123,7 +119,7 @@ if (mPendingTasks.isEmpty()) callback.onAllPaymentAppsCreated(); } }; - additionalFactory.create(context, webContents, methods, cb); + additionalFactory.create(webContents, methods, cb); } } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestFactory.java index bdaedc9..17f19df 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestFactory.java
@@ -4,10 +4,7 @@ package org.chromium.chrome.browser.payments; -import android.app.Activity; - import org.chromium.chrome.browser.ChromeFeatureList; -import org.chromium.content.browser.ContentViewCore; import org.chromium.content_public.browser.WebContents; import org.chromium.mojo.system.MojoException; import org.chromium.payments.mojom.CanMakePaymentQueryResult; @@ -18,7 +15,6 @@ import org.chromium.payments.mojom.PaymentRequest; import org.chromium.payments.mojom.PaymentRequestClient; import org.chromium.services.service_manager.InterfaceFactory; -import org.chromium.ui.base.WindowAndroid; /** * Creates instances of PaymentRequest. @@ -87,15 +83,6 @@ if (mWebContents == null) return new InvalidPaymentRequest(); - ContentViewCore contentViewCore = ContentViewCore.fromWebContents(mWebContents); - if (contentViewCore == null) return new InvalidPaymentRequest(); - - WindowAndroid window = contentViewCore.getWindowAndroid(); - if (window == null) return new InvalidPaymentRequest(); - - Activity context = window.getActivity().get(); - if (context == null) return new InvalidPaymentRequest(); - - return new PaymentRequestImpl(context, mWebContents); + return new PaymentRequestImpl(mWebContents); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java index a9eceba..2d18e5fd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.payments; import android.app.Activity; +import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.os.Handler; @@ -41,6 +42,7 @@ import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType; import org.chromium.chrome.browser.tabmodel.TabModelObserver; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; import org.chromium.components.url_formatter.UrlFormatter; import org.chromium.content_public.browser.WebContents; @@ -230,7 +232,6 @@ }; private final Handler mHandler = new Handler(); - private final ChromeActivity mContext; private final WebContents mWebContents; private final String mMerchantName; private final String mOrigin; @@ -239,7 +240,6 @@ private final CardEditor mCardEditor; private final PaymentRequestJourneyLogger mJourneyLogger = new PaymentRequestJourneyLogger(); - private Bitmap mFavicon; private PaymentRequestClient mClient; /** @@ -274,6 +274,11 @@ private SectionInformation mUiShippingOptions; private Map<String, PaymentMethodData> mMethodData; + private boolean mRequestShipping; + private boolean mRequestPayerName; + private boolean mRequestPayerPhone; + private boolean mRequestPayerEmail; + private int mShippingType; private SectionInformation mShippingAddressesSection; private ContactDetailsSection mContactSection; private List<PaymentApp> mApps; @@ -289,6 +294,8 @@ private boolean mHasRecordedAbortReason; private boolean mQueriedCanMakePayment; private CurrencyFormatter mCurrencyFormatter; + private TabModelSelector mObservedTabModelSelector; + private TabModel mObservedTabModel; /** True if any of the requested payment methods are supported. */ private boolean mArePaymentMethodsSupported; @@ -313,44 +320,23 @@ /** * Builds the PaymentRequest service implementation. * - * @param context The context where PaymentRequest has been invoked. * @param webContents The web contents that have invoked the PaymentRequest API. */ - public PaymentRequestImpl(Activity context, WebContents webContents) { - assert context != null; + public PaymentRequestImpl(WebContents webContents) { assert webContents != null; - assert context instanceof ChromeActivity; - mContext = (ChromeActivity) context; mWebContents = webContents; mMerchantName = webContents.getTitle(); // The feature is available only in secure context, so it's OK to not show HTTPS. mOrigin = UrlFormatter.formatUrlForSecurityDisplay( - webContents.getLastCommittedUrl(), false); + mWebContents.getLastCommittedUrl(), false); mCertificateChain = CertificateChainHelper.getCertificateChain(mWebContents); - final FaviconHelper faviconHelper = new FaviconHelper(); - faviconHelper.getLocalFaviconImageForURL(Profile.getLastUsedProfile(), - webContents.getVisibleUrl(), - mContext.getResources().getDimensionPixelSize(R.dimen.payments_favicon_size), - new FaviconHelper.FaviconImageCallback() { - @Override - public void onFaviconAvailable(Bitmap bitmap, String iconUrl) { - faviconHelper.destroy(); - if (bitmap == null) return; - if (mUI == null) { - mFavicon = bitmap; - return; - } - mUI.setTitleBitmap(bitmap); - } - }); - mApps = new ArrayList<>(); mAddressEditor = new AddressEditor(); - mCardEditor = new CardEditor(webContents, mAddressEditor, sObserverForTest); + mCardEditor = new CardEditor(mWebContents, mAddressEditor, sObserverForTest); if (sCanMakePaymentQueries == null) sCanMakePaymentQueries = new ArrayMap<>(); @@ -392,66 +378,79 @@ if (!parseAndValidateDetailsOrDisconnectFromClient(details)) return; PaymentAppFactory.getInstance().create( - mContext, mWebContents, Collections.unmodifiableSet(mMethodData.keySet()), this); + mWebContents, Collections.unmodifiableSet(mMethodData.keySet()), this); - boolean requestShipping = options != null && options.requestShipping; - boolean requestPayerName = options != null && options.requestPayerName; - boolean requestPayerPhone = options != null && options.requestPayerPhone; - boolean requestPayerEmail = options != null && options.requestPayerEmail; + mRequestShipping = options != null && options.requestShipping; + mRequestPayerName = options != null && options.requestPayerName; + mRequestPayerPhone = options != null && options.requestPayerPhone; + mRequestPayerEmail = options != null && options.requestPayerEmail; + mShippingType = options == null ? PaymentShippingType.SHIPPING : options.shippingType; // If there is a single payment method and the merchant has not requested any other // information, we can safely go directly to the payment app instead of showing // Payment Request UI. mShouldSkipShowingPaymentRequestUi = ChromeFeatureList.isEnabled(ChromeFeatureList.WEB_PAYMENTS_SINGLE_APP_UI_SKIP) - && mMethodData.size() == 1 && !requestShipping && !requestPayerName - && !requestPayerPhone && !requestPayerEmail + && mMethodData.size() == 1 && !mRequestShipping && !mRequestPayerName + && !mRequestPayerPhone && !mRequestPayerEmail // Only allowing payment apps that own their own UIs. // This excludes AutofillPaymentApp as its UI is rendered inline in // the payment request UI, thus can't be skipped. && mMethodData.keySet().iterator().next() != null - && mMethodData.keySet().iterator().next().startsWith( - UrlConstants.HTTPS_URL_PREFIX); + && mMethodData.keySet().iterator().next().startsWith(UrlConstants.HTTPS_URL_PREFIX); + + PaymentRequestMetrics.recordRequestedInformationHistogram(mRequestPayerEmail, + mRequestPayerPhone, mRequestShipping, mRequestPayerName); + } + + private void buildUI(Activity activity) { + assert activity != null; List<AutofillProfile> profiles = null; - if (requestShipping || requestPayerName || requestPayerPhone || requestPayerEmail) { + if (mRequestShipping || mRequestPayerName || mRequestPayerPhone || mRequestPayerEmail) { profiles = PersonalDataManager.getInstance().getProfilesToSuggest( false /* includeNameInLabel */); } - if (requestShipping) { - createShippingSection(Collections.unmodifiableList(profiles)); + if (mRequestShipping) { + createShippingSection(activity, Collections.unmodifiableList(profiles)); } - if (requestPayerName || requestPayerPhone || requestPayerEmail) { + if (mRequestPayerName || mRequestPayerPhone || mRequestPayerEmail) { mContactEditor = - new ContactEditor(requestPayerName, requestPayerPhone, requestPayerEmail); + new ContactEditor(mRequestPayerName, mRequestPayerPhone, mRequestPayerEmail); mContactSection = new ContactDetailsSection( - mContext, Collections.unmodifiableList(profiles), mContactEditor); + activity, Collections.unmodifiableList(profiles), mContactEditor); } - mUI = new PaymentRequestUI(mContext, this, requestShipping, - requestPayerName || requestPayerPhone || requestPayerEmail, + mUI = new PaymentRequestUI(activity, this, mRequestShipping, + mRequestPayerName || mRequestPayerPhone || mRequestPayerEmail, mMerchantSupportsAutofillPaymentInstruments, !PaymentPreferencesUtil.isPaymentCompleteOnce(), mMerchantName, mOrigin, - new ShippingStrings( - options == null ? PaymentShippingType.SHIPPING : options.shippingType)); + new ShippingStrings(mShippingType)); + + final FaviconHelper faviconHelper = new FaviconHelper(); + faviconHelper.getLocalFaviconImageForURL(Profile.getLastUsedProfile(), + mWebContents.getLastCommittedUrl(), + activity.getResources().getDimensionPixelSize(R.dimen.payments_favicon_size), + new FaviconHelper.FaviconImageCallback() { + @Override + public void onFaviconAvailable(Bitmap bitmap, String iconUrl) { + if (bitmap != null) mUI.setTitleBitmap(bitmap); + faviconHelper.destroy(); + } + }); // Add the callback to change the label of shipping addresses depending on the focus. - if (requestShipping) mUI.setShippingAddressSectionFocusChangedObserver(this); - - if (mFavicon != null) mUI.setTitleBitmap(mFavicon); - mFavicon = null; + if (mRequestShipping) mUI.setShippingAddressSectionFocusChangedObserver(this); mAddressEditor.setEditorView(mUI.getEditorView()); mCardEditor.setEditorView(mUI.getCardEditorView()); if (mContactEditor != null) mContactEditor.setEditorView(mUI.getEditorView()); - - PaymentRequestMetrics.recordRequestedInformationHistogram(requestPayerEmail, - requestPayerPhone, requestShipping, requestPayerName); } - private void createShippingSection(List<AutofillProfile> unmodifiableProfiles) { + private void createShippingSection( + Context context, List<AutofillProfile> unmodifiableProfiles) { List<AutofillAddress> addresses = new ArrayList<>(); for (int i = 0; i < unmodifiableProfiles.size(); i++) { @@ -460,7 +459,7 @@ // Only suggest addresses that have a street address. if (!TextUtils.isEmpty(profile.getStreetAddress())) { - addresses.add(new AutofillAddress(mContext, profile)); + addresses.add(new AutofillAddress(context, profile)); } } @@ -517,11 +516,21 @@ setIsShowing(true); if (disconnectIfNoPaymentMethodsSupported()) return; + ChromeActivity chromeActivity = ChromeActivity.fromWebContents(mWebContents); + if (chromeActivity == null) { + disconnectFromClientWithDebugMessage("Unable to find Chrome activity"); + recordAbortReasonHistogram(PaymentRequestMetrics.ABORT_REASON_OTHER); + return; + } + // Catch any time the user switches tabs. Because the dialog is modal, a user shouldn't be // allowed to switch tabs, which can happen if the user receives an external Intent. - mContext.getTabModelSelector().addObserver(mSelectorObserver); - mContext.getCurrentTabModel().addObserver(mTabModelObserver); + mObservedTabModelSelector = chromeActivity.getTabModelSelector(); + mObservedTabModel = chromeActivity.getCurrentTabModel(); + mObservedTabModelSelector.addObserver(mSelectorObserver); + mObservedTabModel.addObserver(mTabModelObserver); + buildUI(chromeActivity); if (!mShouldSkipShowingPaymentRequestUi) mUI.show(); recordSuccessFunnelHistograms("Shown"); mJourneyLogger.setShowCalled(); @@ -1177,9 +1186,16 @@ @Override public void onCardAndAddressSettingsClicked() { + Context context = ChromeActivity.fromWebContents(mWebContents); + if (context == null) { + disconnectFromClientWithDebugMessage("Unable to find Chrome activity"); + recordAbortReasonHistogram(PaymentRequestMetrics.ABORT_REASON_OTHER); + return; + } + Intent intent = PreferencesLauncher.createIntentForSettingsPage( - mContext, AutofillAndPaymentsPreferences.class.getName()); - mContext.startActivity(intent); + context, AutofillAndPaymentsPreferences.class.getName()); + context.startActivity(intent); disconnectFromClientWithDebugMessage("Card and address settings clicked"); recordAbortReasonHistogram(PaymentRequestMetrics.ABORT_REASON_ABORTED_BY_USER); } @@ -1504,8 +1520,15 @@ mPaymentMethodsSection = null; } - mContext.getTabModelSelector().removeObserver(mSelectorObserver); - mContext.getCurrentTabModel().removeObserver(mTabModelObserver); + if (mObservedTabModelSelector != null) { + mObservedTabModelSelector.removeObserver(mSelectorObserver); + mObservedTabModelSelector = null; + } + + if (mObservedTabModel != null) { + mObservedTabModel.removeObserver(mTabModelObserver); + mObservedTabModel = null; + } } private void closeClient() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java index 2847444e..ec61feb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java
@@ -4,7 +4,6 @@ package org.chromium.chrome.browser.payments; -import android.content.Context; import android.graphics.drawable.Drawable; import org.chromium.base.annotations.CalledByNative; @@ -58,7 +57,7 @@ } @Override - public void create(Context context, WebContents webContents, Set<String> methodNames, + public void create(WebContents webContents, Set<String> methodNames, PaymentAppFactory.PaymentAppCreatedCallback callback) { nativeGetAllAppManifests(webContents, callback); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentOption.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentOption.java index 52b80af..72ea333 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentOption.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentOption.java
@@ -126,6 +126,15 @@ } /** + * Updates the label of this option. + * + * @param label The new label to use. + */ + protected void updateLabel(String label) { + mLabels[0] = label; + } + + /** * Updates the sublabel of this option. * * @param sublabel The new sublabel to use. @@ -137,12 +146,17 @@ /** * Updates the tertiary label of this option. * - * @param tetriarylabel The new tertiary label to use. + * @param tertiarylabel The new tertiary label to use. */ protected void updateTertiarylabel(@Nullable String tertiarylabel) { mLabels[2] = tertiarylabel; } + /** @param icon The new icon to use. */ + public void updateDrawableIcon(Drawable icon) { + mIcon = icon; + } + /** @return The drawable icon for this payment option. */ public Drawable getDrawableIcon() { return mIcon;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java index cb0ddbb..7311360 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
@@ -378,7 +378,7 @@ mRequestShipping = requestShipping; mRequestContactDetails = requestContact; mShowDataSource = showDataSource; - mAnimatorTranslation = activity.getResources().getDimensionPixelSize( + mAnimatorTranslation = mContext.getResources().getDimensionPixelSize( R.dimen.payments_ui_translation); mErrorView = (PaymentRequestUiErrorView) LayoutInflater.from(mContext).inflate( @@ -422,7 +422,7 @@ mRequestView = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.payment_request, null); - prepareRequestView(activity, title, origin, canAddCards); + prepareRequestView(mContext, title, origin, canAddCards); // To handle the specced animations, the dialog is entirely contained within a translucent // FrameLayout. This could eventually be converted to a real BottomSheetDialog, but that @@ -527,13 +527,13 @@ * TODO(dfalcantara): Ideally, everything related to the request and its views would just be put * into its own class but that'll require yanking out a lot of this class. * - * @param activity Activity displaying the UI. + * @param context The application context. * @param title Title of the page. * @param origin Host of the page. * @param canAddCards Whether new cards can be added. */ private void prepareRequestView( - Activity activity, String title, String origin, boolean canAddCards) { + Context context, String title, String origin, boolean canAddCards) { mSpinnyLayout = mRequestView.findViewById(R.id.payment_request_spinny); assert mSpinnyLayout.getVisibility() == View.VISIBLE; mIsShowingSpinner = true; @@ -549,12 +549,12 @@ mCloseButton = mRequestView.findViewById(R.id.close_button); mCloseButton.setOnClickListener(this); mPayButton = DualControlLayout.createButtonForLayout( - activity, true, activity.getString(R.string.payments_pay_button), this); + context, true, context.getString(R.string.payments_pay_button), this); mEditButton = DualControlLayout.createButtonForLayout( - activity, false, activity.getString(R.string.payments_edit_button), this); + context, false, context.getString(R.string.payments_edit_button), this); mButtonBar = (DualControlLayout) mRequestView.findViewById(R.id.button_bar); mButtonBar.setAlignment(DualControlLayout.ALIGN_END); - mButtonBar.setStackedMargin(activity.getResources().getDimensionPixelSize( + mButtonBar.setStackedMargin(context.getResources().getDimensionPixelSize( R.dimen.infobar_margin_between_stacked_buttons)); mButtonBar.addView(mPayButton); mButtonBar.addView(mEditButton); @@ -564,19 +564,19 @@ mPaymentContainer = (ScrollView) mRequestView.findViewById(R.id.option_container); mPaymentContainerLayout = (LinearLayout) mRequestView.findViewById(R.id.payment_container_layout); - mOrderSummarySection = new LineItemBreakdownSection(activity, - activity.getString(R.string.payments_order_summary_label), this, - activity.getString(R.string.payments_updated_label)); + mOrderSummarySection = new LineItemBreakdownSection(context, + context.getString(R.string.payments_order_summary_label), this, + context.getString(R.string.payments_updated_label)); mShippingSummarySection = new ExtraTextsSection( - activity, activity.getString(mShippingStrings.getSummaryLabel()), this); + context, context.getString(mShippingStrings.getSummaryLabel()), this); mShippingAddressSection = new OptionSection( - activity, activity.getString(mShippingStrings.getAddressLabel()), this); + context, context.getString(mShippingStrings.getAddressLabel()), this); mShippingOptionSection = new OptionSection( - activity, activity.getString(mShippingStrings.getOptionLabel()), this); + context, context.getString(mShippingStrings.getOptionLabel()), this); mContactDetailsSection = new OptionSection( - activity, activity.getString(R.string.payments_contact_details_label), this); + context, context.getString(R.string.payments_contact_details_label), this); mPaymentMethodSection = new OptionSection( - activity, activity.getString(R.string.payments_method_of_payment_label), this); + context, context.getString(R.string.payments_method_of_payment_label), this); // Some sections conditionally allow adding new options. mShippingOptionSection.setCanAddItems(false);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java index 17221103..c29e184 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java
@@ -92,10 +92,12 @@ * favicons. * @param importantReasons Bitfield of reasons why this domain was selected. Pass this back * to clearBrowinsgData so we can record metrics. + * @param dialogDisabled If the important dialog has been ignored too many times and should + * not be shown. */ @CalledByNative("ImportantSitesCallback") - void onImportantRegisterableDomainsReady( - String[] domains, String[] exampleOrigins, int[] importantReasons); + void onImportantRegisterableDomainsReady(String[] domains, String[] exampleOrigins, + int[] importantReasons, boolean dialogDisabled); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/CreditCardNumberFormattingTextWatcher.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/CreditCardNumberFormattingTextWatcher.java index 20a3077..eebb671a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/CreditCardNumberFormattingTextWatcher.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/CreditCardNumberFormattingTextWatcher.java
@@ -8,6 +8,8 @@ import android.text.TextUtils; import android.text.TextWatcher; +import org.chromium.chrome.browser.autofill.PersonalDataManager; + /** * Watch a TextView and if a credit card number is entered, it will format the number. * Disable formatting when user: @@ -26,7 +28,7 @@ /** * Whether to format the credit card number. If true, spaces will be inserted * automatically between each group of 4 digits in the credit card number as the user types. - * This is set to false if the user types a dash or deletes one of the auto-inserted spaces. + * This is set to false if the user types a dash or space. */ private boolean mFormattingEnabled = true; @@ -50,13 +52,7 @@ } @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - if (mSelfChange || !mFormattingEnabled) return; - // If user deletes non-digit characters, do not format. - if (count > 0 && hasDashOrSpace(s, start, count)) { - mFormattingEnabled = false; - } - } + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void afterTextChanged(Editable s) { @@ -94,7 +90,19 @@ } public static void insertSeparators(Editable s) { - final int[] positions = {4, 9, 14 }; + int[] positions; + if (PersonalDataManager.getInstance() + .getBasicCardPaymentType(s.toString(), false) + .equals("amex")) { + positions = new int[2]; + positions[0] = 4; + positions[1] = 11; + } else { + positions = new int[3]; + positions[0] = 4; + positions[1] = 9; + positions[2] = 14; + } for (int i : positions) { if (s.length() > i) { s.insert(i, SEPARATOR);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java index 800535b..f86b56fc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java
@@ -627,9 +627,9 @@ } @Override - public void onImportantRegisterableDomainsReady( - String[] domains, String[] exampleOrigins, int[] importantReasons) { - if (domains == null) return; + public void onImportantRegisterableDomainsReady(String[] domains, String[] exampleOrigins, + int[] importantReasons, boolean dialogDisabled) { + if (domains == null || dialogDisabled) return; // mMaxImportantSites is a constant on the C++ side. While 0 is valid, use 1 as the minimum // because histogram code assumes a min >= 1; the underflow bucket will record the 0s. RecordHistogram.recordLinearCountHistogram("History.ClearBrowsingData.NumImportant",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/profiles/MostVisitedSites.java b/chrome/android/java/src/org/chromium/chrome/browser/profiles/MostVisitedSites.java index 20534c1..448d11dd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/profiles/MostVisitedSites.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/profiles/MostVisitedSites.java
@@ -5,6 +5,8 @@ package org.chromium.chrome.browser.profiles; import org.chromium.base.annotations.CalledByNative; +import org.chromium.chrome.browser.ntp.MostVisitedTileType.MostVisitedTileTypeEnum; +import org.chromium.chrome.browser.ntp.NTPTileSource.NTPTileSourceEnum; /** * Methods to bridge into native history to provide most recent urls, titles and thumbnails. @@ -119,10 +121,12 @@ /** * Records the opening of a Most Visited Item. * @param index The index of the item that was opened. - * @param tileType The visual type of the item. Valid values are listed in MostVisitedTileType. + * @param type The visual type of the item as defined in {@code MostVisitedTileType}. + * @param source The {@code NTPTileSource} that generated this item. */ - public void recordOpenedMostVisitedItem(int index, int tileType, int source) { - nativeRecordOpenedMostVisitedItem(mNativeMostVisitedSitesBridge, index, tileType, source); + public void recordOpenedMostVisitedItem( + int index, @MostVisitedTileTypeEnum int type, @NTPTileSourceEnum int source) { + nativeRecordOpenedMostVisitedItem(mNativeMostVisitedSitesBridge, index, type, source); } private native long nativeInit(Profile profile);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/OWNERS index bc1cace..f95eb42 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/OWNERS +++ b/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/OWNERS
@@ -1,2 +1,4 @@ johnme@chromium.org peter@chromium.org + +# COMPONENT: Services>CloudMessaging
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/Tile.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/Tile.java index 508fd4b..48a9d3a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/Tile.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/Tile.java
@@ -8,33 +8,39 @@ import android.support.annotation.Nullable; import org.chromium.chrome.browser.ntp.MostVisitedTileType; +import org.chromium.chrome.browser.ntp.MostVisitedTileType.MostVisitedTileTypeEnum; +import org.chromium.chrome.browser.ntp.NTPTileSource.NTPTileSourceEnum; /** - * Holds the details of a site tile. + * Holds the details to populate a site suggestion tile. */ public class Tile { private final String mTitle; private final String mUrl; private final String mWhitelistIconPath; private final boolean mOfflineAvailable; - private int mIndex; - private int mTileType = MostVisitedTileType.NONE; + private final int mIndex; + + @NTPTileSourceEnum private final int mSource; + @MostVisitedTileTypeEnum + private int mType = MostVisitedTileType.NONE; + @Nullable private Drawable mIcon; /** - * @param title The title of the page. - * @param url The URL of the page. + * @param title The tile title. + * @param url The site URL. * @param whitelistIconPath The path to the icon image file, if this is a whitelisted tile. * Empty otherwise. * @param offlineAvailable Whether there is an offline copy of the URL available. * @param index The index of this tile in the list of tiles. - * @param source The {@code MostVisitedSource} that generated this tile. + * @param source The {@code NTPTileSource} that generated this tile. */ public Tile(String title, String url, String whitelistIconPath, boolean offlineAvailable, - int index, int source) { + int index, @NTPTileSourceEnum int source) { mTitle = title; mUrl = url; mWhitelistIconPath = whitelistIconPath; @@ -44,7 +50,7 @@ } /** - * @return The URL of this tile. + * @return The site URL of this tile. */ public String getUrl() { return mUrl; @@ -79,34 +85,29 @@ } /** - * Updates this tile's index in the list of tiles. + * @return The source of this tile. Used for metrics tracking. Valid values are listed in + * {@code NTPTileSource}. */ - public void setIndex(int index) { - mIndex = index; + @NTPTileSourceEnum + public int getSource() { + return mSource; } /** * @return The visual type of this tile. Valid values are listed in * {@link MostVisitedTileType}. */ - public int getTileType() { - return mTileType; + @MostVisitedTileTypeEnum + public int getType() { + return mType; } /** * Sets the visual type of this tile. Valid values are listed in * {@link MostVisitedTileType}. */ - public void setTileType(int type) { - mTileType = type; - } - - /** - * @return The source of this tile. Used for metrics tracking. Valid values are listed in - * {@code MostVisitedSource}. - */ - public int getSource() { - return mSource; + public void setType(@MostVisitedTileTypeEnum int type) { + mType = type; } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java index 1ed21221..d0edcb4e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java
@@ -9,7 +9,6 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.ntp.ContextMenuManager; -import org.chromium.chrome.browser.ntp.MostVisitedLayout; import org.chromium.chrome.browser.ntp.cards.ItemViewType; import org.chromium.chrome.browser.ntp.cards.NewTabPageViewHolder; import org.chromium.chrome.browser.ntp.cards.OptionalLeaf; @@ -73,12 +72,12 @@ * The {@code ViewHolder} for the {@link TileGrid}. */ public static class ViewHolder extends NewTabPageViewHolder { - private final MostVisitedLayout mLayout; + private final TileGridLayout mLayout; public ViewHolder(ViewGroup parentView) { super(LayoutInflater.from(parentView.getContext()) .inflate(R.layout.suggestions_site_tile_grid, parentView, false)); - mLayout = (MostVisitedLayout) itemView; + mLayout = (TileGridLayout) itemView; } public void onBindViewHolder(TileGroup tileGroup) { @@ -87,7 +86,7 @@ } public void updateIconView(Tile tile) { - mLayout.updateIconView(tile.getUrl(), tile.getIcon()); + mLayout.updateIconView(tile); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGridLayout.java similarity index 81% rename from chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedLayout.java rename to chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGridLayout.java index 47c99aa..b445745 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGridLayout.java
@@ -2,11 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.chrome.browser.ntp; +package org.chromium.chrome.browser.suggestions; import android.content.Context; import android.content.res.Resources; -import android.graphics.drawable.Drawable; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; @@ -17,10 +16,9 @@ import org.chromium.chrome.browser.util.MathUtils; /** - * A layout that arranges most visited items in a grid. + * A layout that arranges tiles in a grid. */ -public class MostVisitedLayout extends FrameLayout { - +public class TileGridLayout extends FrameLayout { private static final int MAX_COLUMNS = 4; private int mVerticalSpacing; @@ -34,16 +32,16 @@ * @param context The view context in which this item will be shown. * @param attrs The attributes of the XML tag that is inflating the view. */ - public MostVisitedLayout(Context context, AttributeSet attrs) { + public TileGridLayout(Context context, AttributeSet attrs) { super(context, attrs); Resources res = getResources(); - mVerticalSpacing = res.getDimensionPixelOffset(R.dimen.most_visited_vertical_spacing); - mMinHorizontalSpacing = res.getDimensionPixelOffset( - R.dimen.most_visited_min_horizontal_spacing); - mMaxHorizontalSpacing = res.getDimensionPixelOffset( - R.dimen.most_visited_max_horizontal_spacing); - mMaxWidth = res.getDimensionPixelOffset(R.dimen.most_visited_layout_max_width); + mVerticalSpacing = res.getDimensionPixelOffset(R.dimen.tile_grid_layout_vertical_spacing); + mMinHorizontalSpacing = + res.getDimensionPixelOffset(R.dimen.tile_grid_layout_min_horizontal_spacing); + mMaxHorizontalSpacing = + res.getDimensionPixelOffset(R.dimen.tile_grid_layout_max_horizontal_spacing); + mMaxWidth = res.getDimensionPixelOffset(R.dimen.tile_grid_layout_max_width); } /** @@ -70,15 +68,14 @@ /** * Sets a new icon on the child view with a matching URL. - * @param url The site URL of the child tile view. - * @param icon The icon to set. + * @param tile The tile that holds the data to populate the tile view. */ - public void updateIconView(String url, Drawable icon) { + public void updateIconView(Tile tile) { int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { - MostVisitedItemView tileView = (MostVisitedItemView) getChildAt(i); - if (TextUtils.equals(url, tileView.getUrl())) { - tileView.setIcon(icon); + TileView tileView = (TileView) getChildAt(i); + if (TextUtils.equals(tile.getUrl(), tileView.getTile().getUrl())) { + tileView.renderIcon(); break; } } @@ -104,8 +101,8 @@ int childHeight = getChildAt(0).getMeasuredHeight(); int childWidth = getChildAt(0).getMeasuredWidth(); int numColumns = MathUtils.clamp( - (gridWidth + mMinHorizontalSpacing) / (childWidth + mMinHorizontalSpacing), - 1, MAX_COLUMNS); + (gridWidth + mMinHorizontalSpacing) / (childWidth + mMinHorizontalSpacing), 1, + MAX_COLUMNS); // Ensure column spacing isn't greater than mMaxHorizontalSpacing. int gridWidthMinusColumns = Math.max(0, gridWidth - numColumns * childWidth);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java index 655e154..7540667c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java
@@ -30,15 +30,15 @@ import org.chromium.chrome.browser.favicon.LargeIconBridge.LargeIconCallback; import org.chromium.chrome.browser.ntp.ContextMenuManager; import org.chromium.chrome.browser.ntp.ContextMenuManager.ContextMenuItemId; -import org.chromium.chrome.browser.ntp.MostVisitedItemView; import org.chromium.chrome.browser.ntp.MostVisitedTileType; -import org.chromium.chrome.browser.ntp.TitleUtil; import org.chromium.chrome.browser.profiles.MostVisitedSites.MostVisitedURLsObserver; import org.chromium.chrome.browser.widget.RoundedIconGenerator; import org.chromium.ui.mojom.WindowOpenDisposition; import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; /** @@ -137,7 +137,7 @@ mObserver = observer; Resources resources = mContext.getResources(); - mDesiredIconSize = resources.getDimensionPixelSize(R.dimen.most_visited_icon_size); + mDesiredIconSize = resources.getDimensionPixelSize(R.dimen.tile_view_icon_size); // On ldpi devices, mDesiredIconSize could be even smaller than ICON_MIN_SIZE_PX. mMinIconSize = Math.min(mDesiredIconSize, ICON_MIN_SIZE_PX); int desiredIconSizeDp = @@ -193,11 +193,43 @@ mTileGroupDelegate.setMostVisitedURLsObserver(this, maxResults); } - public void renderTileViews(ViewGroup parentView, boolean trackLoadTasks) { - parentView.removeAllViews(); + /** + * Renders tile views in the given {@link TileGridLayout}, reusing existing tile views where + * possible because view inflation and icon loading are slow. + * @param tileGridLayout The layout to render the tile views into. + * @param trackLoadTasks Whether to track load tasks. + */ + public void renderTileViews(TileGridLayout tileGridLayout, boolean trackLoadTasks) { + // Map the old tile views by url so they can be reused later. + Map<String, TileView> oldTileViews = new HashMap<>(); + int childCount = tileGridLayout.getChildCount(); + for (int i = 0; i < childCount; i++) { + TileView tileView = (TileView) tileGridLayout.getChildAt(i); + oldTileViews.put(tileView.getTile().getUrl(), tileView); + } + + // Remove all views from the layout because even if they are reused later they'll have to be + // added back in the correct order. + tileGridLayout.removeAllViews(); for (final Tile tile : mTiles) { - View tileView = buildTileView(tile, parentView, trackLoadTasks); + // First see if an old view can be reused. + if (oldTileViews.containsKey(tile.getUrl())) { + TileView oldTileView = oldTileViews.get(tile.getUrl()); + if (TextUtils.equals(tile.getTitle(), oldTileView.getTile().getTitle()) + && tile.isOfflineAvailable() == oldTileView.getTile().isOfflineAvailable() + && TextUtils.equals(tile.getWhitelistIconPath(), + oldTileView.getTile().getWhitelistIconPath())) { + tileGridLayout.addView(oldTileView); + + // Re-render the icon because it may not have been painted when re-added. + oldTileView.renderIcon(); + continue; + } + } + + // No view was reused, create a new one. + TileView tileView = buildTileView(tile, tileGridLayout, trackLoadTasks); tileView.setOnClickListener(new OnClickListener() { @Override @@ -237,8 +269,7 @@ }); } }); - - parentView.addView(tileView); + tileGridLayout.addView(tileView); } } @@ -252,43 +283,16 @@ private void buildTiles(String[] titles, String[] urls, String[] whitelistIconPaths, @Nullable Set<String> offlineUrls, int[] sources) { - Tile[] oldTiles = mTiles; - int oldTileCount = oldTiles == null ? 0 : oldTiles.length; + int oldTileCount = mTiles == null ? 0 : mTiles.length; mTiles = new Tile[titles.length]; boolean isInitialLoad = !mHasReceivedData; mHasReceivedData = true; - // Add the tile views to the layout. for (int i = 0; i < titles.length; i++) { - String url = urls[i]; - String title = titles[i]; - String whitelistIconPath = whitelistIconPaths[i]; - int source = sources[i]; - boolean offlineAvailable = offlineUrls != null && offlineUrls.contains(url); - - // Look for an existing tile to reuse. - // TODO(mvanouwerkerk): Ensure we don't create views and load icons more often than - // necessary. - Tile tile = null; - for (int j = 0; j < oldTileCount; j++) { - Tile oldTile = oldTiles[j]; - if (oldTile != null && TextUtils.equals(url, oldTile.getUrl()) - && TextUtils.equals(title, oldTile.getTitle()) - && offlineAvailable == oldTile.isOfflineAvailable() - && whitelistIconPath.equals(oldTile.getWhitelistIconPath())) { - tile = oldTile; - tile.setIndex(i); - oldTiles[j] = null; - break; - } - } - - // If nothing can be reused, create a new tile. - if (tile == null) { - tile = new Tile(title, url, whitelistIconPath, offlineAvailable, i, source); - } - mTiles[i] = tile; + boolean offlineAvailable = offlineUrls != null && offlineUrls.contains(urls[i]); + mTiles[i] = new Tile( + titles[i], urls[i], whitelistIconPaths[i], offlineAvailable, i, sources[i]); } if (oldTileCount != mTiles.length) mObserver.onTileCountChanged(); @@ -299,14 +303,17 @@ mObserver.onTileDataChanged(); } - private View buildTileView(Tile tile, ViewGroup parentView, boolean trackLoadTask) { - MostVisitedItemView view = - (MostVisitedItemView) LayoutInflater.from(parentView.getContext()) - .inflate(R.layout.most_visited_item, parentView, false); - view.setTitle(TitleUtil.getTitleForDisplay(tile.getTitle(), tile.getUrl())); - view.setOfflineAvailable(tile.isOfflineAvailable()); - view.setIcon(tile.getIcon()); - view.setUrl(tile.getUrl()); + /** + * Inflates a new tile view, initializes it, and loads an icon for it. + * @param tile The tile that holds the data to populate the new tile view. + * @param parentView The parent of the new tile view. + * @param trackLoadTask Whether to track a load task. + * @return The new tile view. + */ + private TileView buildTileView(Tile tile, ViewGroup parentView, boolean trackLoadTask) { + TileView tileView = (TileView) LayoutInflater.from(parentView.getContext()) + .inflate(R.layout.tile_view, parentView, false); + tileView.initialize(tile); LargeIconCallback iconCallback = new LargeIconCallbackImpl(tile, trackLoadTask); if (trackLoadTask) mObserver.onLoadTaskAdded(); @@ -314,7 +321,7 @@ mUiDelegate.getLargeIconForUrl(tile.getUrl(), mMinIconSize, iconCallback); } - return view; + return tileView; } private boolean loadWhitelistIcon(Tile tile, LargeIconCallback iconCallback) { @@ -346,8 +353,8 @@ mIconGenerator.setBackgroundColor(fallbackColor); icon = mIconGenerator.generateIconForUrl(mTile.getUrl()); mTile.setIcon(new BitmapDrawable(mContext.getResources(), icon)); - mTile.setTileType(isFallbackColorDefault ? MostVisitedTileType.ICON_DEFAULT - : MostVisitedTileType.ICON_COLOR); + mTile.setType(isFallbackColorDefault ? MostVisitedTileType.ICON_DEFAULT + : MostVisitedTileType.ICON_COLOR); } else { RoundedBitmapDrawable roundedIcon = RoundedBitmapDrawableFactory.create(mContext.getResources(), icon); @@ -358,7 +365,7 @@ roundedIcon.setAntiAlias(true); roundedIcon.setFilterBitmap(true); mTile.setIcon(roundedIcon); - mTile.setTileType(MostVisitedTileType.ICON_REAL); + mTile.setType(MostVisitedTileType.ICON_REAL); } mObserver.onTileIconChanged(mTile); if (mTrackLoadTask) mObserver.onLoadTaskCompleted();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java index 2779b77d..3c1fda1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java
@@ -88,20 +88,20 @@ } @Override - public void onLoadingComplete(Tile[] items) { + public void onLoadingComplete(Tile[] tiles) { assert !mIsDestroyed; - int tileTypes[] = new int[items.length]; - int sources[] = new int[items.length]; - String tileUrls[] = new String[items.length]; + int types[] = new int[tiles.length]; + int sources[] = new int[tiles.length]; + String urls[] = new String[tiles.length]; - for (int i = 0; i < items.length; i++) { - tileTypes[i] = items[i].getTileType(); - sources[i] = items[i].getSource(); - tileUrls[i] = items[i].getUrl(); + for (int i = 0; i < tiles.length; i++) { + types[i] = tiles[i].getType(); + sources[i] = tiles[i].getSource(); + urls[i] = tiles[i].getUrl(); } - mMostVisitedSites.recordPageImpression(tileTypes, sources, tileUrls); + mMostVisitedSites.recordPageImpression(types, sources, urls); } @Override @@ -109,6 +109,9 @@ assert !mIsDestroyed; mIsDestroyed = true; + if (mTileRemovedSnackbarController != null) { + mTab.getSnackbarManager().dismissSnackbars(mTileRemovedSnackbarController); + } mMostVisitedSites.destroy(); } @@ -154,7 +157,7 @@ NewTabPageUma.recordExplicitUserNavigation( tile.getUrl(), NewTabPageUma.RAPPOR_ACTION_VISITED_SUGGESTED_TILE); mMostVisitedSites.recordOpenedMostVisitedItem( - tile.getIndex(), tile.getTileType(), tile.getSource()); + tile.getIndex(), tile.getType(), tile.getSource()); } @TargetApi(Build.VERSION_CODES.LOLLIPOP)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileView.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileView.java new file mode 100644 index 0000000..b9bde01af --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileView.java
@@ -0,0 +1,61 @@ +// 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. + +package org.chromium.chrome.browser.suggestions; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import org.chromium.chrome.R; +import org.chromium.chrome.browser.ntp.TitleUtil; + +/** + * The view for a site suggestion tile. Displays the title of the site beneath a large icon. If a + * large icon isn't available, displays a rounded rectangle with a single letter in its place. + */ +public class TileView extends FrameLayout { + /** + * The tile that holds the data to populate this view. + */ + private Tile mTile; + + /** + * Constructor for inflating from XML. + */ + public TileView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + /** + * Initializes the view using the data held by {@code tile}. This should be called immediately + * after inflation. + * @param tile The tile that holds the data to populate this view. + */ + public void initialize(Tile tile) { + mTile = tile; + ((TextView) findViewById(R.id.tile_view_title)) + .setText(TitleUtil.getTitleForDisplay(mTile.getTitle(), mTile.getUrl())); + renderIcon(); + findViewById(R.id.offline_badge) + .setVisibility(mTile.isOfflineAvailable() ? View.VISIBLE : View.GONE); + } + + /** + * @return The tile that holds the data to populate this view. + */ + public Tile getTile() { + return mTile; + } + + /** + * Renders the icon held by the {@link Tile} or clears it from the view if the icon is null. + */ + public void renderIcon() { + ((ImageView) findViewById(R.id.tile_view_icon)).setImageDrawable(mTile.getIcon()); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java index 82d3f434..2eb8d89 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
@@ -6,6 +6,7 @@ import android.content.Context; import android.util.AttributeSet; +import android.view.ViewGroup; import org.chromium.chrome.R; import org.chromium.chrome.browser.widget.BottomSheet; @@ -33,8 +34,8 @@ @Override protected int getProgressBarTopMargin() { // In the case where the toolbar is at the bottom of the screen, the progress bar should - // be at the top of the toolbar. - return getContext().getResources().getDimensionPixelSize(R.dimen.toolbar_shadow_height); + // be at the top of the screen. + return 0; } @Override @@ -60,4 +61,13 @@ return mBottomSheet.getSheetState() != BottomSheet.SHEET_STATE_PEEK || mBottomSheet.isRunningSettleAnimation() || super.shouldIgnoreSwipeGesture(); } + + @Override + protected void addProgressBarToHierarchy() { + if (mProgressBar == null) return; + + ViewGroup coordinator = (ViewGroup) getRootView().findViewById(R.id.coordinator); + coordinator.addView(mProgressBar); + mProgressBar.setProgressBarContainer(coordinator); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java index 0f134fb..e628967 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
@@ -69,7 +69,7 @@ private ToolbarDataProvider mToolbarDataProvider; private ToolbarTabController mToolbarTabController; @Nullable - private ToolbarProgressBar mProgressBar; + protected ToolbarProgressBar mProgressBar; private boolean mNativeLibraryReady; private boolean mUrlHasFocus; @@ -245,17 +245,24 @@ recordFirstDrawTime(); } + /** + * Add the toolbar's progress bar to the view hierarchy. + */ + protected void addProgressBarToHierarchy() { + if (mProgressBar == null) return; + + ViewGroup controlContainer = + (ViewGroup) getRootView().findViewById(R.id.control_container); + int progressBarPosition = UiUtils.insertAfter( + controlContainer, mProgressBar, (View) getParent()); + assert progressBarPosition >= 0; + mProgressBar.setProgressBarContainer(controlContainer); + } + @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - if (mProgressBar != null) { - ViewGroup controlContainer = - (ViewGroup) getRootView().findViewById(R.id.control_container); - int progressBarPosition = UiUtils.insertAfter( - controlContainer, mProgressBar, (View) getParent()); - assert progressBarPosition >= 0; - mProgressBar.setControlContainer(controlContainer); - } + addProgressBarToHierarchy(); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java index b73fc416..10ec297 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java
@@ -11,12 +11,17 @@ import android.provider.Settings; import android.support.v7.app.AlertDialog; +import org.chromium.base.Callback; import org.chromium.base.ContextUtils; import org.chromium.base.Log; import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.library_loader.LibraryLoader; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeApplication; import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeVersionInfo; +import org.chromium.chrome.browser.externalauth.ExternalAuthUtils; +import org.chromium.chrome.browser.externalauth.UserRecoverableErrorHandler; import org.chromium.chrome.browser.preferences.ChromePreferenceManager; import org.chromium.webapk.lib.client.WebApkValidator; @@ -26,6 +31,9 @@ public class ChromeWebApkHost { private static final String TAG = "ChromeWebApkHost"; + /** Whether installing WebAPks from Google Play is possible. */ + private static Boolean sCanUseGooglePlayInstall; + private static Boolean sEnabledForTesting; public static void init() { @@ -53,14 +61,70 @@ return installingFromUnknownSourcesAllowed() || canUseGooglePlayToInstallWebApk(); } - /** Return whether installing WebAPKs using Google Play is enabled. */ - public static boolean canUseGooglePlayToInstallWebApk() { - return isEnabled() && nativeCanUseGooglePlayToInstallWebApk(); + /** + * Initializes {@link sCanUseGooglePlayInstall}. It checks whether: + * 1) WebAPKs are enabled. + * 2) Google Play Service is available on the device. + * 3) Google Play install is enabled by Chrome. + * 4) Google Play is up-to-date and with gServices flags turned on. + * It calls the Google Play Install API to update {@link sCanUseGooglePlayInstall} + * asynchronously. + */ + public static void initCanUseGooglePlayToInstallWebApk() { + if (!isGooglePlayInstallEnabledByChromeFeature() + || !ExternalAuthUtils.getInstance().canUseGooglePlayServices( + ContextUtils.getApplicationContext(), + new UserRecoverableErrorHandler.Silent())) { + sCanUseGooglePlayInstall = false; + return; + } + + ChromeApplication application = (ChromeApplication) ContextUtils.getApplicationContext(); + GooglePlayWebApkInstallDelegate delegate = application.getGooglePlayWebApkInstallDelegate(); + if (delegate == null) { + sCanUseGooglePlayInstall = false; + return; + } + + Callback<Boolean> callback = new Callback<Boolean>() { + @Override + public void onResult(Boolean success) { + sCanUseGooglePlayInstall = success; + } + }; + delegate.canInstallWebApk(callback); } + /** + * Returns whether installing WebAPKs from Google Play is possible. + * If {@link sCanUseGooglePlayInstall} hasn't been set yet, it returns false immediately and + * calls the Google Play Install API to update {@link sCanUseGooglePlayInstall} asynchronously. + */ + public static boolean canUseGooglePlayToInstallWebApk() { + if (sCanUseGooglePlayInstall == null) { + sCanUseGooglePlayInstall = false; + initCanUseGooglePlayToInstallWebApk(); + } + return sCanUseGooglePlayInstall; + } + + /** + * Returns whether Google Play install is enabled by Chrome. Does not check whether installing + * from Google Play is possible. + */ + public static boolean isGooglePlayInstallEnabledByChromeFeature() { + return isEnabled() && LibraryLoader.isInitialized() + && nativeCanUseGooglePlayToInstallWebApk(); + } + + /** + * Returns whether installing WebAPKs is possible either from "unknown resources" or Google + * Play. + */ @CalledByNative - private static boolean areWebApkEnabled() { - return ChromeWebApkHost.isEnabled(); + private static boolean canInstallWebApk() { + return isEnabled() + && (canUseGooglePlayToInstallWebApk() || nativeCanInstallFromUnknownSources()); } /** @@ -155,4 +219,5 @@ } private static native boolean nativeCanUseGooglePlayToInstallWebApk(); + private static native boolean nativeCanInstallFromUnknownSources(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/GooglePlayWebApkInstallDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/GooglePlayWebApkInstallDelegate.java index 5bcfc29..ca5992c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/GooglePlayWebApkInstallDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/GooglePlayWebApkInstallDelegate.java
@@ -51,4 +51,10 @@ * @param event The result of the install. */ void onGotInstallEvent(String packageName, @InstallerPackageEvent int event); + + /** + * Checks whether Google Play Install API is available. + * @param callback The callback to invoke when the check is done. + */ + void canInstallWebApk(Callback<Boolean> callback); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java index 50ee188..9b95ea93 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java
@@ -55,7 +55,18 @@ String url = urlFromIntent(intent); int source = sourceFromIntent(intent); + return create(webApkPackageName, url, source); + } + /** + * Constructs a WebApkInfo from the passed in parameters and <meta-data> in the WebAPK's Android + * manifest. + * + * @param webApkPackageName The package name of the WebAPK. + * @param url Url that the WebAPK should navigate to when launched. + * @param source Source that the WebAPK was launched from. + */ + public static WebApkInfo create(String webApkPackageName, String url, int source) { // Unlike non-WebAPK web apps, WebAPK ids are predictable. A malicious actor may send an // intent with a valid start URL and arbitrary other data. Only use the start URL, the // package name and the ShortcutSource from the launch intent and extract the remaining data
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java index a32ff99e..1f466cda 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java
@@ -20,8 +20,6 @@ import org.chromium.chrome.browser.ChromeApplication; import org.chromium.chrome.browser.ShortcutHelper; import org.chromium.chrome.browser.banners.InstallerDelegate; -import org.chromium.chrome.browser.externalauth.ExternalAuthUtils; -import org.chromium.chrome.browser.externalauth.UserRecoverableErrorHandler; import org.chromium.chrome.browser.util.IntentUtils; import java.io.File; @@ -65,10 +63,7 @@ @CalledByNative private boolean canUseGooglePlayInstallService() { - return mGooglePlayWebApkInstallDelegate != null - && ExternalAuthUtils.getInstance().canUseGooglePlayServices( - ContextUtils.getApplicationContext(), - new UserRecoverableErrorHandler.Silent()); + return ChromeWebApkHost.canUseGooglePlayToInstallWebApk(); } @CalledByNative @@ -118,20 +113,27 @@ @CalledByNative private boolean installWebApkFromGooglePlayAsync(String packageName, int version, String title, String token, String url) { - if (mGooglePlayWebApkInstallDelegate == null) return false; + if (mGooglePlayWebApkInstallDelegate == null) { + notify(false); + return false; + } Callback<Boolean> callback = new Callback<Boolean>() { @Override public void onResult(Boolean success) { - if (mNativePointer != 0) { - nativeOnInstallFinished(mNativePointer, success); - } + WebApkInstaller.this.notify(success); } }; return mGooglePlayWebApkInstallDelegate.installAsync(packageName, version, title, token, url, callback); } + private void notify(boolean success) { + if (mNativePointer != 0) { + nativeOnInstallFinished(mNativePointer, success); + } + } + /** * Updates a WebAPK. * @param filePath File to update.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java index d492c5d..ccbbd5a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java
@@ -6,7 +6,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Region; import android.support.annotation.IntDef; @@ -22,6 +22,7 @@ import android.widget.FrameLayout; import org.chromium.base.ApiCompatibilityUtils; +import org.chromium.base.ObserverList; import org.chromium.chrome.R; import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager; import org.chromium.chrome.browser.suggestions.SuggestionsBottomSheetContent; @@ -41,7 +42,7 @@ * All the computation in this file is based off of the bottom of the screen instead of the top * for simplicity. This means that the bottom of the screen is 0 on the Y axis. */ -public class BottomSheet extends FrameLayout { +public class BottomSheet extends FrameLayout implements FadingBackgroundView.FadingViewObserver { /** The different states that the bottom sheet can have. */ @IntDef({SHEET_STATE_PEEK, SHEET_STATE_HALF, SHEET_STATE_FULL}) @Retention(RetentionPolicy.SOURCE) @@ -76,6 +77,9 @@ /** The interpolator that the height animator uses. */ private final Interpolator mInterpolator = new DecelerateInterpolator(1.0f); + /** The list of observers of this sheet. */ + private final ObserverList<BottomSheetObserver> mObservers = new ObserverList<>(); + /** This is a cached array for getting the window location of different views. */ private final int[] mLocationArray = new int[2]; @@ -89,7 +93,7 @@ private VelocityTracker mVelocityTracker; /** The animator used to move the sheet to a fixed state when released by the user. */ - private ObjectAnimator mSettleAnimator; + private ValueAnimator mSettleAnimator; /** The height of the toolbar. */ private float mToolbarHeight; @@ -125,6 +129,12 @@ private FrameLayout mBottomSheetContentContainer; /** + * The last ratio sent to observers of onTransitionPeekToHalf(). This is used to ensure the + * final value sent to these observers is 1.0f. + */ + private float mLastPeekToHalfRatioSent; + + /** * An interface defining content that can be displayed inside of the bottom sheet for Chrome * Home. */ @@ -178,8 +188,7 @@ float currentShownRatio = mContainerHeight > 0 ? getSheetOffsetFromBottom() / mContainerHeight : 0; boolean isSheetInMaxPosition = - MathUtils.areFloatsEqual(currentShownRatio, - mStateRatios[mStateRatios.length - 1]); + MathUtils.areFloatsEqual(currentShownRatio, getFullRatio()); RecyclerView scrollingView = null; if (mSheetContent != null) scrollingView = mSheetContent.getScrollingContentView(); @@ -199,7 +208,7 @@ } // Similarly, if the sheet is in the min position, don't move if the scroll is downward. - if (currentShownRatio <= mStateRatios[0] && distanceY < 0) { + if (currentShownRatio <= getPeekRatio() && distanceY < 0) { mIsScrolling = false; return false; } @@ -450,8 +459,7 @@ mStateRatios[0] = mToolbarHeight / mContainerHeight; // Compute the height that the content section of the bottom sheet. - float contentHeight = - (mContainerHeight * mStateRatios[mStateRatios.length - 1]) - mToolbarHeight; + float contentHeight = (mContainerHeight * getFullRatio()) - mToolbarHeight; MarginLayoutParams sheetContentParams = (MarginLayoutParams) mBottomSheetContentContainer.getLayoutParams(); @@ -481,8 +489,8 @@ */ private void createSettleAnimation(@SheetState int targetState) { mCurrentState = targetState; - mSettleAnimator = ObjectAnimator.ofFloat( - this, View.TRANSLATION_Y, mContainerHeight - getSheetHeightForState(targetState)); + mSettleAnimator = ValueAnimator.ofFloat(getSheetOffsetFromBottom(), + getSheetHeightForState(targetState)); mSettleAnimator.setDuration(BASE_ANIMATION_DURATION_MS); mSettleAnimator.setInterpolator(mInterpolator); @@ -494,6 +502,13 @@ } }); + mSettleAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animator) { + setSheetOffsetFromBottom((Float) animator.getAnimatedValue()); + } + }); + mSettleAnimator.start(); } @@ -514,7 +529,7 @@ * @return The max offset. */ private float getMaxOffset() { - return mStateRatios[mStateRatios.length - 1] * mContainerHeight; + return getFullRatio() * mContainerHeight; } /** @@ -522,7 +537,7 @@ * @return The min offset. */ private float getMinOffset() { - return mStateRatios[0] * mContainerHeight; + return getPeekRatio() * mContainerHeight; } /** @@ -539,6 +554,52 @@ */ private void setSheetOffsetFromBottom(float offset) { setTranslationY(mContainerHeight - offset); + sendUpdatePeekToHalfEvent(); + } + + /** + * @return The ratio of the height of the screen that the peeking state is. + */ + private float getPeekRatio() { + return mStateRatios[0]; + } + + /** + * @return The ratio of the height of the screen that the half expanded state is. + */ + private float getHalfRatio() { + return mStateRatios[1]; + } + + /** + * @return The ratio of the height of the screen that the fully expanded state is. + */ + private float getFullRatio() { + return mStateRatios[2]; + } + + /** + * Sends a notification if the sheet is transitioning from the peeking to half expanded state. + * This method only sends events when the sheet is between the peeking and half states. + */ + private void sendUpdatePeekToHalfEvent() { + float screenRatio = + mContainerHeight > 0 ? getSheetOffsetFromBottom() / mContainerHeight : 0; + + // This ratio is relative to the peek and half positions of the sheet rather than the height + // of the screen. + float peekHalfRatio = MathUtils.clamp( + (screenRatio - getPeekRatio()) / (getHalfRatio() - getPeekRatio()), 0, 1); + + // If the ratio is close enough to zero, just set it to zero. + if (MathUtils.areFloatsEqual(peekHalfRatio, 0f)) peekHalfRatio = 0f; + + for (BottomSheetObserver o : mObservers) { + if (mLastPeekToHalfRatioSent < 1f || peekHalfRatio < 1f) { + mLastPeekToHalfRatioSent = peekHalfRatio; + o.onTransitionPeekToHalf(peekHalfRatio); + } + } } /** @@ -583,6 +644,14 @@ } /** + * Adds an observer to the bottom sheet. + * @param observer The observer to add. + */ + public void addObserver(BottomSheetObserver observer) { + mObservers.addObserver(observer); + } + + /** * Gets the target state of the sheet based on the sheet's height and velocity. * @param sheetHeight The current height of the sheet. * @param yVelocity The current Y velocity of the sheet. This is only used for determining the @@ -621,4 +690,12 @@ } return prevState; } + + @Override + public void onFadingViewClick() { + setSheetState(SHEET_STATE_PEEK, true); + } + + @Override + public void onFadingViewHidden() {} }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheetObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheetObserver.java new file mode 100644 index 0000000..37aa70e --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheetObserver.java
@@ -0,0 +1,20 @@ +// 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. + +package org.chromium.chrome.browser.widget; + +/** + * An interface for notifications about the state of the bottom sheet. + */ +public interface BottomSheetObserver { + /** + * An event for when the sheet is transitioning from the peeking state to the half expanded + * state. Once the sheet is outside the peek-half range, this event will no longer be + * called. + * @param transitionFraction The fraction of the way to the half expanded state that the + * sheet is. This will be 0.0f when the sheet is peeking and 1.0f + * when the sheet is half expanded. + */ + void onTransitionPeekToHalf(float transitionFraction); +} \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/FadingBackgroundView.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/FadingBackgroundView.java index af504e0..2135dfa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/FadingBackgroundView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/FadingBackgroundView.java
@@ -18,8 +18,8 @@ * This view is used to obscure content and bring focus to a foreground view (i.e. the Chrome Home * bottom sheet or the omnibox suggestions). */ -public class FadingBackgroundView extends View implements View.OnClickListener { - +public class FadingBackgroundView extends View implements View.OnClickListener, + BottomSheetObserver { /** * An interface for listening to events on the fading view. */ @@ -142,4 +142,9 @@ public void onClick(View view) { for (FadingViewObserver o : mObservers) o.onFadingViewClick(); } + + @Override + public void onTransitionPeekToHalf(float transitionFraction) { + setViewAlpha(transitionFraction); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java index 95232c3..1d5a925 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java
@@ -78,7 +78,7 @@ private AnimationLogic mAnimationLogic; private boolean mAnimationInitialized; private int mMarginTop; - private ViewGroup mControlContainer; + private ViewGroup mProgressBarContainer; private int mProgressStartCount; private int mThemeColor; @@ -167,10 +167,10 @@ } /** - * @param container This View's container. + * @param container The view containing the progress bar. */ - public void setControlContainer(ViewGroup container) { - mControlContainer = container; + public void setProgressBarContainer(ViewGroup container) { + mProgressBarContainer = container; } @Override @@ -225,7 +225,7 @@ } else { setForegroundColor(getForegroundColor()); } - UiUtils.insertAfter(mControlContainer, mAnimatingView, this); + UiUtils.insertAfter(mProgressBarContainer, mAnimatingView, this); } else if (TextUtils.equals(animation, "fast-start")) { mAnimationLogic = new ProgressAnimationFastStart(); } else if (TextUtils.equals(animation, "linear")) {
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd index 8fca2d2f..d11ff6a9 100644 --- a/chrome/android/java/strings/android_chrome_strings.grd +++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -270,7 +270,7 @@ <!-- Autofill and Payments preferences --> <message name="IDS_PREFS_AUTOFILL_AND_PAYMENTS" desc="Title of Autofill and payments settings prefrences. [CHAR-LIMIT=32]"> Autofill and payments - </message> + </message> <message name="IDS_AUTOFILL_SWITCH" desc="Title for 'Autofill forms' switch preference, which controls whether personal data can be automatically filled into web page forms. [CHAR-LIMIT=32]"> Autofill forms </message> @@ -2624,197 +2624,6 @@ <ph name="BEGIN_LINK"><link></ph>Get help<ph name="END_LINK"></link></ph> </message> - <!-- Payments --> - <message name="IDS_PAYMENTS_NAME_FIELD_IN_CONTACT_DETAILS" desc="The label for text input field containing the full name of a person. [CHAR-LIMIT=32]"> - Name - </message> - <message name="IDS_PAYMENTS_SAVE_CARD_TO_DEVICE_CHECKBOX" desc="The label for the checkbox that enables the user to save a credit card to their device, for example, on their phone."> - Save this card to this device - </message> - <message name="IDS_PAYMENTS_ACCEPTED_CARDS_LABEL" desc="The title for the section that displays the credit card types that the merchant accepts."> - Cards accepted - </message> - <message name="IDS_PAYMENTS_METHOD_OF_PAYMENT_LABEL" desc="The title for the section that lets the user select the method of payment."> - Payment - </message> - <message name="IDS_PAYMENTS_CONTACT_DETAILS_LABEL" desc="The title for the section that lets the user select how they can be contacted."> - Contact info - </message> - <message name="IDS_PAYMENTS_ADD_CONTACT_DETAILS_LABEL" desc="The title of the dialog for user to add new contact information, such as the user's full name, an email address or a phone number."> - Add contact info - </message> - <message name="IDS_PAYMENTS_EDIT_CONTACT_DETAILS_LABEL" desc="The title of the dialog for user to edit their contact information, such as the user's full name, an email address or a phone number."> - Edit contact info - </message> - <message name="IDS_PAYMENTS_ADD_CARD" desc="The title of the dialog for user to add new payment card."> - Add card - </message> - <message name="IDS_PAYMENTS_BILLING_ADDRESS_REQUIRED" desc="The label to indicate billing address is required for payment card."> - Billing address required - </message> - <message name="IDS_PAYMENTS_ADD_BILLING_ADDRESS" desc="The title of the dialog for user to add billing address to payment card."> - Add billing address - </message> - <message name="IDS_PAYMENTS_NAME_ON_CARD_REQUIRED" desc="The label to indicate name on card is required for payment card."> - Name on card required - </message> - <message name="IDS_PAYMENTS_ADD_NAME_ON_CARD" desc="The title of the dialog for user to add name on card to payment card."> - Add name on card - </message> - <message name="IDS_PAYMENTS_CARD_NUMBER_INVALID" desc="The label to indicate payment card number is invalid."> - Card number invalid - </message> - <message name="IDS_PAYMENTS_ADD_VALID_CARD_NUMBER" desc="The title of the dialog for user to add valid payment card number."> - Add valid card number - </message> - <message name="IDS_PAYMENTS_MORE_INFORMATION_REQUIRED" desc="The label to indicate more information is required for payment card or shipping address or contact info."> - More information required - </message> - <message name="IDS_PAYMENTS_ADD_MORE_INFORMATION" desc="The title of the dialog for user to add more information to payment card or shipping address or contact info."> - Add more information - </message> - <message name="IDS_PAYMENTS_EDIT_CARD" desc="The title of the dialog for user to edit payment card."> - Edit card - </message> - <message name="IDS_PAYMENTS_CREDIT_CARD_EXPIRATION_DATE_ABBR" desc="Abbreviated label for credit card expiration date. [CHAR-LIMIT=32]"> - Exp: <ph name="EXPIRATION_MONTH">%1$s<ex>06</ex></ph>/<ph name="EXPIRATION_YEAR">%2$s<ex>17</ex></ph> - </message> - <message name="IDS_PAYMENTS_PHONE_NUMBER_REQUIRED" desc="The label to indicate phone number is required in the shipping address or contact info. This phone number can be used, for example, if there's a problem with shipping a package to its destination."> - Phone number required - </message> - <message name="IDS_PAYMENTS_ADD_PHONE_NUMBER" desc="The title of the dialog for user to add phone number to the shipping address or contact info. This phone number can be used, for example, if there's a problem with shipping a package to its destination."> - Add phone number - </message> - <message name="IDS_PAYMENTS_RECIPIENT_REQUIRED" desc="The label to indicate recipient is required in the shipping address. The recipient could be a person or institute name identifies the receiver of the shipping package."> - Recipient required - </message> - <message name="IDS_PAYMENTS_ADD_RECIPIENT" desc="The title of the dialog for user to add recipient in the shipping address. The recipient could be a person or institute name identifies the receiver of the shipping package."> - Add recipient - </message> - <message name="IDS_PAYMENTS_INVALID_ADDRESS" desc="The label to indicate the shipping address is invalid. For example, missing state or city name."> - Invalid address - </message> - <message name="IDS_PAYMENTS_ADD_VALID_ADDRESS" desc="The title of the dialog for user to add valid shipping address. For example, missing state or city name."> - Add valid address - </message> - <message name="IDS_PAYMENTS_EMAIL_REQUIRED" desc="The label to indicate email is required for the contact details. This email can be used to contact the payer."> - Email required - </message> - <message name="IDS_PAYMENTS_ADD_EMAIL" desc="The title of the dialog for user to add email to the contact details. This email can be used to contact the payer."> - Add email - </message> - <message name="IDS_PAYMENTS_NAME_REQUIRED" desc="The label to indicate name is required for the contact details. This name could be a person or institute name of the payer."> - Name required - </message> - <message name="IDS_PAYMENTS_ADD_NAME" desc="The title of the dialog for user to add name to the contact details. This name could be a person or institute name of the payer."> - Add name - </message> - <message name="IDS_PAYMENTS_ORDER_SUMMARY_LABEL" desc="The title of the section that shows the summary of the order, including names and prices of individual line items, i.e. the bill."> - Order summary - </message> - <message name="IDS_PAYMENTS_EDIT_BUTTON" desc="The label for the button that lets the user edit their payment options."> - Edit - </message> - <message name="IDS_PAYMENTS_PAY_BUTTON" desc="The label for the button that finishes the payment process."> - Pay - </message> - <message name="IDS_PAYMENTS_LOADING_MESSAGE" desc="The text that informs the user that payment information is being loaded up."> - Loading - </message> - <message name="IDS_PAYMENTS_ERROR_MESSAGE" desc="The text that informs the user that there is error in verifying and charging the payment."> - There was an error processing your order. Please check your account and try again. - </message> - <message name="IDS_PAYMENTS_REQUIRED_FIELD_MESSAGE" desc="The text that informs the user that '*' character indicates an input field that is required. The '*' character should not be changed."> - * indicates required field - </message> - <message name="IDS_PAYMENTS_FIELD_REQUIRED_VALIDATION_MESSAGE" desc="The text that informs the user that an input field is required."> - Required field - </message> - <message name="IDS_PAYMENTS_PHONE_INVALID_VALIDATION_MESSAGE" desc="The text that informs the user that the phone number they have entered is not valid."> - Invalid phone number - </message> - <message name="IDS_PAYMENTS_EMAIL_INVALID_VALIDATION_MESSAGE" desc="The text that informs the user that the email address they have entered is not valid."> - Invalid email address - </message> - <message name="IDS_PAYMENTS_CARD_NUMBER_INVALID_VALIDATION_MESSAGE" desc="The text that informs the user that the credit card number they have entered is not valid."> - Invalid card number - </message> - <message name="IDS_PAYMENTS_CARD_EXPIRATION_INVALID_VALIDATION_MESSAGE" desc="The text that informs the user that the credit card expiration date they have entered is not valid."> - Invalid expiration date - </message> - <message name="IDS_PAYMENTS_ADD_CONTACT" desc="Text on a button that lets a user add new contact details, like the user's full name, an email address or a phone number."> - Add contact info - </message> - <message name="IDS_PAYMENTS_CHECKING_OPTION" desc="Text explaining that the option the user selected is being checked and verified."> - Checking - </message> - <message name="IDS_PAYMENTS_UPDATED_LABEL" desc="The text that informs the user that the total value of their cart has been updated."> - Updated - </message> - <message name="IDS_PAYMENTS_CARD_AND_ADDRESS_SETTINGS" desc="Label of the section containing the link to go to the settings page for card and address options."> - You can manage cards and addresses in <ph name="BEGIN_LINK"><link></ph>Settings<ph name="END_LINK"></link></ph>. - </message> - <message name="IDS_PAYMENTS_CARD_AND_ADDRESS_SETTINGS_SIGNED_IN" desc="Label of the section containing the origin description and the link to go to the settings page for card and address options. This label is used when the user is signed in."> - Card and address options are from your Google Account (<ph name="ACCOUNT_EMAIL">%1$s<ex>johndoe@gmail.com</ex></ph>) and Chrome. You can manage these in <ph name="BEGIN_LINK"><link></ph>Settings<ph name="END_LINK"></link></ph>. - </message> - <message name="IDS_PAYMENTS_CARD_AND_ADDRESS_SETTINGS_SIGNED_OUT" desc="Label of the section containing the origin description and the link to go to the settings page for card and address options. This label is used when the user is not signed in."> - Card and address options are from Chrome. You can manage these in <ph name="BEGIN_LINK"><link></ph>Settings<ph name="END_LINK"></link></ph>. - </message> - - <!-- Shipping address in web payments API --> - <message name="IDS_PAYMENTS_SHIPPING_SUMMARY_LABEL" desc="The title for the section of shipping information. Shipping is typically used for packages."> - Shipping - </message> - <message name="IDS_PAYMENTS_SHIPPING_ADDRESS_LABEL" desc="The title for the section that lets the user select the address where the product should be shipped. Shipping is typically used for packages."> - Shipping address - </message> - <message name="IDS_PAYMENTS_SHIPPING_OPTION_LABEL" desc="The title for the section that lets the user select how the product should be shipped. Shipping is typically used for packages."> - Shipping option - </message> - <message name="IDS_PAYMENTS_SELECT_SHIPPING_ADDRESS_FOR_SHIPPING_METHODS" desc="Text implying that a user needs to pick a shipping address to see the shipping methods. Shipping is typically used for packages."> - Select a shipping address to check shipping methods and requirements. - </message> - <message name="IDS_PAYMENTS_UNSUPPORTED_SHIPPING_ADDRESS" desc="Text implying that a user needs to pick a different shipping address, because the currently selected address is not supported. Shipping is typically used for packages."> - Unsupported shipping address. Select a different address. - </message> - - <!-- Delivery address in web payments API --> - <message name="IDS_PAYMENTS_DELIVERY_SUMMARY_LABEL" desc="The title for the section of delivery information. Delivery is commonly faster than shipping. For example, it might be used for food delivery."> - Delivery - </message> - <message name="IDS_PAYMENTS_DELIVERY_ADDRESS_LABEL" desc="The title for the section that lets the user select the address where the product should be delivered. Delivery is commonly faster than shipping. For example, it might be used for food delivery."> - Delivery address - </message> - <message name="IDS_PAYMENTS_DELIVERY_OPTION_LABEL" desc="The title for the section that lets the user select how the product should be delivered. Delivery is commonly faster than shipping. For example, it might be used for food delivery."> - Delivery option - </message> - <message name="IDS_PAYMENTS_SELECT_DELIVERY_ADDRESS_FOR_DELIVERY_METHODS" desc="Text implying that a user needs to pick a delivery address to see the delivery methods. Delivery is commonly faster than shipping. For example, it might be used for food delivery."> - Select a delivery address to check delivery methods and requirements. - </message> - <message name="IDS_PAYMENTS_UNSUPPORTED_DELIVERY_ADDRESS" desc="Text implying that a user needs to pick a different delivery address, because the currently selected address is not supported. Delivery is commonly faster than shipping. For example, it might be used for food delivery."> - Unsupported delivery address. Select a different address. - </message> - - <!-- Pickup address in web payments API --> - <message name="IDS_PAYMENTS_PICKUP_SUMMARY_LABEL" desc="The title for the section of pickup information. For example, this could be the address for laundry pickup."> - Pickup - </message> - <message name="IDS_PAYMENTS_PICKUP_ADDRESS_LABEL" desc="The title for the section that lets the user select the address where their item should be picked up. For example, this item could be laundry to be cleaned."> - Pickup address - </message> - <message name="IDS_PAYMENTS_PICKUP_OPTION_LABEL" desc="The title for the section that lets the user select how their item should be picked up. This item can be laundry to be cleaned, for example."> - Pickup option - </message> - <message name="IDS_PAYMENTS_SELECT_PICKUP_ADDRESS_FOR_PICKUP_METHODS" desc="Text implying that a user needs to choose a pickup address to see the pickup methods. For example, this could be the address for laundry pickup."> - Select a pickup address to check pickup methods and requirements. - </message> - <message name="IDS_PAYMENTS_UNSUPPORTED_PICKUP_ADDRESS" desc="Text implying that a user needs to choose a different pickup address, because the currently selected address is not supported. This address can be used, for example, for laundry pickup."> - Unsupported pickup address. Select a different address. - </message> - <message name="IDS_PAYMENTS_ANDROID_APP_ERROR" desc="Error message that is shown when an Android payment application fails to start."> - Unable to launch payment app. - </message> - <!-- Migration strings --> <message name="IDS_TAB_SWITCHER_CALLOUT_HEADER" desc="Header for the Tab Switcher callout."> Quickly switch tabs
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index ed9780e..f3fe5c9 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -559,8 +559,6 @@ "java/src/org/chromium/chrome/browser/ntp/IncognitoNewTabPageView.java", "java/src/org/chromium/chrome/browser/ntp/LogoBridge.java", "java/src/org/chromium/chrome/browser/ntp/LogoView.java", - "java/src/org/chromium/chrome/browser/ntp/MostVisitedItemView.java", - "java/src/org/chromium/chrome/browser/ntp/MostVisitedLayout.java", "java/src/org/chromium/chrome/browser/ntp/NativePageAssassin.java", "java/src/org/chromium/chrome/browser/ntp/NativePageDialog.java", "java/src/org/chromium/chrome/browser/ntp/NativePageFactory.java", @@ -638,6 +636,8 @@ "java/src/org/chromium/chrome/browser/omaha/MarketURLGetter.java", "java/src/org/chromium/chrome/browser/omaha/OmahaBase.java", "java/src/org/chromium/chrome/browser/omaha/OmahaClient.java", + "java/src/org/chromium/chrome/browser/omaha/OmahaDelegate.java", + "java/src/org/chromium/chrome/browser/omaha/OmahaDelegateImpl.java", "java/src/org/chromium/chrome/browser/omaha/RequestData.java", "java/src/org/chromium/chrome/browser/omaha/RequestFailureException.java", "java/src/org/chromium/chrome/browser/omaha/RequestGenerator.java", @@ -920,8 +920,10 @@ "java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java", "java/src/org/chromium/chrome/browser/suggestions/Tile.java", "java/src/org/chromium/chrome/browser/suggestions/TileGrid.java", + "java/src/org/chromium/chrome/browser/suggestions/TileGridLayout.java", "java/src/org/chromium/chrome/browser/suggestions/TileGroup.java", "java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java", + "java/src/org/chromium/chrome/browser/suggestions/TileView.java", "java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegate.java", "java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java", "java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegate.java", @@ -1095,6 +1097,7 @@ "java/src/org/chromium/chrome/browser/widget/AlertDialogEditText.java", "java/src/org/chromium/chrome/browser/widget/AlwaysDismissedDialog.java", "java/src/org/chromium/chrome/browser/widget/BottomSheet.java", + "java/src/org/chromium/chrome/browser/widget/BottomSheetObserver.java", "java/src/org/chromium/chrome/browser/widget/BoundedLinearLayout.java", "java/src/org/chromium/chrome/browser/widget/ClipDrawableProgressBar.java", "java/src/org/chromium/chrome/browser/widget/CompatibilityTextInputLayout.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/MainActivityWithURLTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/MainActivityWithURLTest.java index 74c71e4..d231e27 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/MainActivityWithURLTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/MainActivityWithURLTest.java
@@ -59,13 +59,13 @@ } /** - * Launch a NTP for most_visited and make sure it loads correctly. This makes sure + * Launch a NTP and make sure it loads correctly. This makes sure the * NTP loading complete notification is received. */ @SmallTest @Feature({"Navigation"}) public void testNewTabPageLaunch() throws Exception { - // Launch chrome with NTP for most_visited + // Launch chrome with NTP. startMainActivityWithURL(UrlConstants.NTP_URL); String currentUrl = getActivity().getActivityTab().getUrl(); assertNotNull(currentUrl);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/SmartClipProviderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/SmartClipProviderTest.java index c0e24a8..3d522ce 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/SmartClipProviderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/SmartClipProviderTest.java
@@ -7,7 +7,6 @@ import android.annotation.TargetApi; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.graphics.Rect; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -54,16 +53,11 @@ return mHtml; } - public Rect getRect() { - return mRect; - } - - public void notifyCalled(String title, String url, String text, String html, Rect rect) { + public void notifyCalled(String title, String url, String text, String html) { mTitle = title; mUrl = url; mText = text; mHtml = html; - mRect = rect; super.notifyCalled(); } @@ -71,7 +65,6 @@ private String mUrl; private String mText; private String mHtml; - private Rect mRect; } private ChromeActivity mActivity; @@ -132,9 +125,8 @@ String title = bundle.getString("title"); String text = bundle.getString("text"); String html = bundle.getString("html"); - Rect rect = bundle.getParcelable("rect"); // We don't care about other values for now. - mCallbackHelper.notifyCalled(title, url, text, html, rect); + mCallbackHelper.notifyCalled(title, url, text, html); return true; } @@ -191,6 +183,5 @@ assertEquals("about:blank", mCallbackHelper.getUrl()); assertNotNull(mCallbackHelper.getText()); assertNotNull(mCallbackHelper.getHtml()); - assertNotNull(mCallbackHelper.getRect()); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java index eaeb963a..ee63be0 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
@@ -63,7 +63,7 @@ private Tab mTab; private NewTabPage mNtp; private View mFakebox; - private ViewGroup mMostVisitedLayout; + private ViewGroup mTileGridLayout; private String[] mFakeMostVisitedUrls; private FakeMostVisitedSites mFakeMostVisitedSites; private EmbeddedTestServer mTestServer; @@ -108,8 +108,8 @@ assertTrue(mTab.getNativePage() instanceof NewTabPage); mNtp = (NewTabPage) mTab.getNativePage(); mFakebox = mNtp.getView().findViewById(R.id.search_box); - mMostVisitedLayout = (ViewGroup) mNtp.getView().findViewById(R.id.most_visited_layout); - assertEquals(mFakeMostVisitedUrls.length, mMostVisitedLayout.getChildCount()); + mTileGridLayout = (ViewGroup) mNtp.getView().findViewById(R.id.tile_grid_layout); + assertEquals(mFakeMostVisitedUrls.length, mTileGridLayout.getChildCount()); } @MediumTest @@ -118,7 +118,7 @@ public void testRender() throws IOException { ViewRenderer viewRenderer = new ViewRenderer(getActivity(), "chrome/test/data/android/render_tests", "NewTabPageTest"); - viewRenderer.renderAndCompare(mMostVisitedLayout, "most_visited"); + viewRenderer.renderAndCompare(mTileGridLayout, "most_visited"); viewRenderer.renderAndCompare(mFakebox, "fakebox"); viewRenderer.renderAndCompare(mNtp.getView().getRootView(), "new_tab_page"); @@ -234,7 +234,7 @@ ChromeTabUtils.waitForTabPageLoaded(mTab, new Runnable() { @Override public void run() { - View mostVisitedItem = mMostVisitedLayout.getChildAt(0); + View mostVisitedItem = mTileGridLayout.getChildAt(0); singleClickView(mostVisitedItem); } }); @@ -248,7 +248,7 @@ @SmallTest @Feature({"NewTabPage"}) public void testOpenMostVisitedItemInNewTab() throws InterruptedException { - invokeContextMenuAndOpenInANewTab(mMostVisitedLayout.getChildAt(0), + invokeContextMenuAndOpenInANewTab(mTileGridLayout.getChildAt(0), ContextMenuManager.ID_OPEN_IN_NEW_TAB, false, mFakeMostVisitedUrls[0]); } @@ -258,7 +258,7 @@ @SmallTest @Feature({"NewTabPage"}) public void testOpenMostVisitedItemInIncognitoTab() throws InterruptedException { - invokeContextMenuAndOpenInANewTab(mMostVisitedLayout.getChildAt(0), + invokeContextMenuAndOpenInANewTab(mTileGridLayout.getChildAt(0), ContextMenuManager.ID_OPEN_IN_INCOGNITO_TAB, true, mFakeMostVisitedUrls[0]); } @@ -268,10 +268,10 @@ @SmallTest @Feature({"NewTabPage"}) public void testRemoveMostVisitedItem() { - View mostVisitedItem = mMostVisitedLayout.getChildAt(0); + View mostVisitedItem = mTileGridLayout.getChildAt(0); ArrayList<View> views = new ArrayList<>(); - mMostVisitedLayout.findViewsWithText(views, FAKE_MOST_VISITED_TITLES[0], - View.FIND_VIEWS_WITH_TEXT); + mTileGridLayout.findViewsWithText( + views, FAKE_MOST_VISITED_TITLES[0], View.FIND_VIEWS_WITH_TEXT); assertEquals(1, views.size()); TestTouchUtils.longClickView(getInstrumentation(), mostVisitedItem);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/OmahaClientTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/OmahaClientTest.java index cb9e1e3..6c40881 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/OmahaClientTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/OmahaClientTest.java
@@ -4,18 +4,14 @@ package org.chromium.chrome.browser.omaha; -import android.app.AlarmManager; -import android.app.PendingIntent; +import android.app.Service; import android.content.Context; -import android.content.Intent; import android.content.SharedPreferences; -import android.content.pm.ApplicationInfo; import android.support.test.filters.SmallTest; import android.test.InstrumentationTestCase; import org.chromium.base.test.util.AdvancedMockContext; import org.chromium.base.test.util.Feature; -import org.chromium.chrome.test.omaha.AttributeFinder; import org.chromium.chrome.test.omaha.MockRequestGenerator; import org.chromium.chrome.test.omaha.MockRequestGenerator.DeviceType; @@ -28,475 +24,75 @@ import java.net.MalformedURLException; import java.net.SocketTimeoutException; import java.net.URL; -import java.util.HashSet; +import java.util.ArrayList; import java.util.LinkedList; +import java.util.List; /** * Tests for the {@link OmahaClient}. - * Tests often override the original OmahaClient's functions with the HookedOmahaClient, which + * Tests override the original OmahaClient's functions with the MockOmahaClient, which * provides a way to hook into functions to return values that would normally be provided by the * system, such as whether Chrome was installed through the system image. */ public class OmahaClientTest extends InstrumentationTestCase { - private enum ServerResponse { - SUCCESS, FAILURE - } + private static class TimestampPair { + public long timestampNextRequest; + public long timestampNextPost; - private enum ConnectionStatus { - RESPONDS, TIMES_OUT - } - - private enum InstallEvent { - SEND, DONT_SEND - } - - private enum PostStatus { - DUE, NOT_DUE - } - - private AdvancedMockContext mContext; - private HookedOmahaClient mOmahaClient; - - @Override - protected void setUp() { - Context targetContext = getInstrumentation().getTargetContext(); - mContext = new AdvancedMockContext(targetContext); - mOmahaClient = HookedOmahaClient.create(mContext); - } - - /** - * If a request exists during handleInitialize(), a POST Intent should be fired immediately. - */ - @SmallTest - @Feature({"Omaha"}) - public void testInitializeWithRequest() { - mOmahaClient.registerNewRequest(10); - - Intent intent = OmahaClient.createInitializeIntent(mContext); - mOmahaClient.onHandleIntent(intent); - assertTrue("OmahaClient has no registered request", mOmahaClient.hasRequest()); - assertTrue("Alarm does not have the correct state", mOmahaClient.getRequestAlarmWasSet()); - assertEquals("OmahaClient didn't post the request", - OmahaClient.POST_RESULT_SCHEDULED, mOmahaClient.mPostResult); - } - - /** - * If a request doesn't exist during handleInitialize(), no intent should be fired. - */ - @SmallTest - @Feature({"Omaha"}) - public void testInitializeWithoutRequest() { - Intent intent = OmahaClient.createInitializeIntent(mContext); - mOmahaClient.onHandleIntent(intent); - assertFalse("OmahaClient has a registered request", mOmahaClient.hasRequest()); - assertTrue("Alarm does not have the correct state", mOmahaClient.getRequestAlarmWasSet()); - assertEquals("OmahaClient called handlePostRequest", -1, mOmahaClient.mPostResult); - } - - /** - * Catch situations where the install source isn't set prior to restoring a saved request. - */ - @SmallTest - @Feature({"Omaha"}) - public void testInstallSourceSetBeforeRestoringRequest() { - // Plant a failed request. - Context targetContext = getInstrumentation().getTargetContext(); - AdvancedMockContext mockContext = new AdvancedMockContext(targetContext); - SharedPreferences prefs = OmahaBase.getSharedPreferences(mockContext); - SharedPreferences.Editor editor = prefs.edit(); - editor.putLong(OmahaBase.PREF_TIMESTAMP_OF_REQUEST, 0); - editor.putString(OmahaBase.PREF_PERSISTED_REQUEST_ID, "persisted_id"); - editor.apply(); - - // Send it off and don't crash when the state is restored and the XML is generated. - HookedOmahaClient omahaClient = HookedOmahaClient.create(mockContext); - omahaClient.mMockScheduler.setCurrentTime(1000); - Intent postIntent = OmahaClient.createPostRequestIntent(mockContext); - omahaClient.onHandleIntent(postIntent); - - // Check that the request was actually generated and tried to be sent. - MockConnection connection = omahaClient.getLastConnection(); - assertTrue("Didn't try to make a connection.", connection.getSentRequest()); - assertFalse("OmahaClient still has a registered request", omahaClient.hasRequest()); - assertTrue("Failed to send request", omahaClient.getCumulativeFailedAttempts() == 0); - } - - /** - * Makes sure that we don't generate a request if we don't have to. - */ - @SmallTest - @Feature({"Omaha", "Main"}) - public void testOmahaClientDoesNotGenerateRequest() { - // Change the time so the OmahaClient thinks no request is necessary. - mOmahaClient.mMockScheduler.setCurrentTime(-1000); - Intent intent = OmahaClient.createRegisterRequestIntent(mContext); - mOmahaClient.onHandleIntent(intent); - assertFalse("OmahaClient has a registered request", mOmahaClient.hasRequest()); - assertEquals(-1, mOmahaClient.mPostResult); - } - - /** - * Makes sure that firing a XML request triggers a post intent. - */ - @SmallTest - @Feature({"Omaha", "Main"}) - public void testOmahaClientRequestToPost() { - // Change the time so the OmahaClient thinks a request is overdue. - mOmahaClient.mMockScheduler.setCurrentTime(1000); - Intent intent = OmahaClient.createRegisterRequestIntent(mContext); - mOmahaClient.onHandleIntent(intent); - assertFalse("OmahaClient has no registered request", mOmahaClient.hasRequest()); - assertEquals(OmahaClient.POST_RESULT_SENT, mOmahaClient.mPostResult); - } - - /** - * Makes sure that incorrect timestamps are caught. - */ - @SmallTest - @Feature({"Omaha"}) - public void testIncorrectDelays() { - // Set the time to be 2 days past epoch, then generate a request. - final long millisecondsPerDay = 86400000; - long currentTimestamp = millisecondsPerDay * 2; - mOmahaClient.mMockScheduler.setCurrentTime(currentTimestamp); - Intent intent = OmahaClient.createRegisterRequestIntent(mContext); - mOmahaClient.onHandleIntent(intent); - - // Rewind the clock 2 days. - currentTimestamp -= millisecondsPerDay * 2; - mOmahaClient.mMockScheduler.setCurrentTime(currentTimestamp); - - // Restore state and confirm that the post timestamp was reset, since it's larger than the - // exponential backoff delay. - HookedOmahaClient secondClient = HookedOmahaClient.create(mContext); - assertEquals("Post timestamp was not cleared.", - 0, secondClient.getTimestampForNextPostAttempt()); - - // Confirm that the request timestamp was reset, since the next timestamp is more than - // a day away. - assertEquals("Request timestamp was not cleared.", - 0, secondClient.getTimestampForNewRequest()); - } - - /** - * Checks that reading and writing out the preferences works. - */ - @SmallTest - @Feature({"Omaha"}) - public void testOmahaClientFileIO() { - // Register and send a request, which saves timestamps to disk. - Intent intent = OmahaClient.createRegisterRequestIntent(mContext); - mOmahaClient.onHandleIntent(intent); - - // The second OmahaClient should know the next timestamp. - HookedOmahaClient secondClient = HookedOmahaClient.create(mContext); - assertEquals("The next timestamp wasn't correct", - OmahaClient.MS_BETWEEN_REQUESTS, secondClient.getTimestampForNewRequest()); - } - - @SmallTest - @Feature({"Omaha"}) - public void testOmahaClientPostHandsetFailure() { - postRequestToServer(DeviceType.HANDSET, ServerResponse.FAILURE, ConnectionStatus.RESPONDS, - InstallEvent.DONT_SEND, PostStatus.DUE); - } - - @SmallTest - @Feature({"Omaha"}) - public void testOmahaClientPostHandsetSuccess() { - postRequestToServer(DeviceType.HANDSET, ServerResponse.SUCCESS, ConnectionStatus.RESPONDS, - InstallEvent.DONT_SEND, PostStatus.DUE); - } - - @SmallTest - @Feature({"Omaha"}) - public void testOmahaClientPostTabletFailure() { - postRequestToServer(DeviceType.TABLET, ServerResponse.FAILURE, ConnectionStatus.RESPONDS, - InstallEvent.DONT_SEND, PostStatus.DUE); - } - - @SmallTest - @Feature({"Omaha"}) - public void testOmahaClientPostTabletSuccess() { - postRequestToServer(DeviceType.TABLET, ServerResponse.SUCCESS, ConnectionStatus.RESPONDS, - InstallEvent.DONT_SEND, PostStatus.DUE); - } - - @SmallTest - @Feature({"Omaha"}) - public void testOmahaClientPostHandsetTimeout() { - postRequestToServer(DeviceType.HANDSET, ServerResponse.FAILURE, ConnectionStatus.TIMES_OUT, - InstallEvent.DONT_SEND, PostStatus.DUE); - } - - @SmallTest - @Feature({"Omaha"}) - public void testOmahaClientPostInstallEventSuccess() { - postRequestToServer(DeviceType.HANDSET, ServerResponse.SUCCESS, ConnectionStatus.RESPONDS, - InstallEvent.SEND, PostStatus.DUE); - } - - @SmallTest - @Feature({"Omaha"}) - public void testOmahaClientPostInstallEventFailure() { - postRequestToServer(DeviceType.HANDSET, ServerResponse.FAILURE, ConnectionStatus.RESPONDS, - InstallEvent.SEND, PostStatus.DUE); - } - - @SmallTest - @Feature({"Omaha"}) - public void testOmahaClientPostWhenNotDue() { - postRequestToServer(DeviceType.HANDSET, ServerResponse.FAILURE, ConnectionStatus.RESPONDS, - InstallEvent.DONT_SEND, PostStatus.NOT_DUE); - } - - /** - * Pretends to post a request to the Omaha server. - * @param deviceType Whether or not to use an app-ID indicating a tablet. - * @param response Whether the server acknowledged the request correctly. - * @param connectionStatus Whether the connection times out when it tries to contact the - * Omaha server. - * @param installType Whether we're sending an install event or not. - * @param postStatus Whether we're due for a POST or not. - */ - public void postRequestToServer(DeviceType deviceType, ServerResponse response, - ConnectionStatus connectionStatus, InstallEvent installType, PostStatus postStatus) { - final boolean succeeded = response == ServerResponse.SUCCESS; - final boolean sentInstallEvent = installType == InstallEvent.SEND; - - HookedOmahaClient omahaClient = new HookedOmahaClient(mContext, deviceType, response, - connectionStatus, false); - omahaClient.onCreate(); - omahaClient.restoreState(mContext); - - // Set whether or not we're sending the install event. - assertTrue("Should default to sending install event.", omahaClient.isSendInstallEvent()); - omahaClient.setSendInstallEvent(installType == InstallEvent.SEND); - omahaClient.registerNewRequest(0); - - // Set up the POST request. - if (postStatus == PostStatus.NOT_DUE) { - // Rewind the clock so that we don't send the request yet. - omahaClient.mMockScheduler.setCurrentTime(-1000); - } - Intent postIntent = OmahaClient.createPostRequestIntent(mContext); - omahaClient.onHandleIntent(postIntent); - - assertTrue("hasRequest() returned wrong value", succeeded != omahaClient.hasRequest()); - if (postStatus == PostStatus.NOT_DUE) { - // No POST attempt was made. - assertTrue("POST was attempted and failed.", - omahaClient.getCumulativeFailedAttempts() == 0); - assertTrue("POST alarm wasn't set for reattempt", omahaClient.getPOSTAlarmWasSet()); - } else { - // Since we start with no failures, the counter incrementing should indicate whether it - // succeeded or not. - assertEquals("Expected different outcome", succeeded, - omahaClient.getCumulativeFailedAttempts() == 0); - assertTrue("Alarm state was changed when it shouldn't have been", - succeeded != omahaClient.getPOSTAlarmWasSet()); - - // If we're sending an install event, we will immediately attempt to send a ping in a - // follow-up request. - int numExpectedRequests = succeeded && sentInstallEvent ? 2 : 1; - assertEquals("Didn't send the correct number of XML requests.", numExpectedRequests, - omahaClient.getNumConnectionsMade()); - - MockConnection connection = omahaClient.getLastConnection(); - assertEquals("Didn't try to make a connection.", true, connection.getSentRequest()); - - if (connectionStatus == ConnectionStatus.TIMES_OUT) { - // Several events shouldn't happen if the connection times out. - assertEquals("Retrieved response code when it should have bailed earlier.", - 0, connection.getNumTimesResponseCodeRetrieved()); - assertFalse("Grabbed input stream when it should have bailed earlier.", - connection.getGotInputStream()); - } - } - - // Check that the latest version and market URLs were saved correctly. - String expectedVersion = succeeded ? MockConnection.UPDATE_VERSION : ""; - String expectedURL = succeeded ? MockConnection.STRIPPED_MARKET_URL : ""; - - // Make sure we properly parsed out the server's response. - assertEquals("Latest version numbers didn't match", expectedVersion, - VersionNumberGetter.getInstance().getLatestKnownVersion(mContext)); - assertEquals( - "Market URL didn't match", expectedURL, MarketURLGetter.getMarketUrl(mContext)); - - // Check that the install event was sent properly. - if (sentInstallEvent) { - assertFalse("OmahaPingService is going to send another install <event>.", - succeeded == omahaClient.isSendInstallEvent()); + public TimestampPair(long timestampNextRequest, long timestampNextPost) { + this.timestampNextRequest = timestampNextRequest; + this.timestampNextPost = timestampNextPost; } } - /** - * Test whether we're using request and session IDs properly for POSTs. - */ - @SmallTest - @Feature({"Omaha"}) - public void testRequestAndSessionIDs() { - assertTrue("Should default to sending install event.", mOmahaClient.isSendInstallEvent()); + private static class MockOmahaDelegate extends OmahaDelegate { + private final List<Integer> mPostResults = new ArrayList<Integer>(); + private final List<Boolean> mGenerateAndPostRequestResults = new ArrayList<Boolean>(); - // Send the POST request. - mOmahaClient.registerNewRequest(0); - Intent postIntent = OmahaClient.createPostRequestIntent(mContext); - mOmahaClient.onHandleIntent(postIntent); - - // If we're sending an install event, we will immediately attempt to send a ping in a - // follow-up request. These should have the same session ID, but different request IDs. - int numRequests = mOmahaClient.getNumConnectionsMade(); - - HashSet<String> sessionIDs = new HashSet<String>(); - HashSet<String> requestIDs = new HashSet<String>(); - for (int i = 0; i < numRequests; ++i) { - String request = mOmahaClient.getConnection(i).getOutputStreamContents(); - - String sessionID = - new AttributeFinder(request, "request", "sessionid").getValue(); - assertNotNull(sessionID); - sessionIDs.add(sessionID); - - String requestID = - new AttributeFinder(request, "request", "requestid").getValue(); - assertNotNull(requestID); - requestIDs.add(requestID); - } - assertEquals("Session ID was not the same across all requests", 1, - sessionIDs.size()); - assertEquals("Request ID was duplicated", numRequests, requestIDs.size()); - - // Send another XML request and make sure the IDs are all different. - assertFalse("OmahaPingService is going to send another install <event>.", - mOmahaClient.isSendInstallEvent()); - mOmahaClient.registerNewRequest(0); - postIntent = OmahaClient.createPostRequestIntent(mContext); - mOmahaClient.onHandleIntent(postIntent); - - assertEquals("Didn't send the correct number of XML requests.", numRequests + 1, - mOmahaClient.getNumConnectionsMade()); - String newRequest = mOmahaClient.getConnection(numRequests).getOutputStreamContents(); - - String newSessionID = new AttributeFinder(newRequest, "request", "sessionid").getValue(); - assertNotNull(newSessionID); - assertFalse("Session ID was reused.", sessionIDs.contains(newSessionID)); - - String newRequestID = new AttributeFinder(newRequest, "request", "requestid").getValue(); - assertNotNull(newRequestID); - assertFalse("Request ID was reused.", requestIDs.contains(newRequestID)); - } - - /** - * Checks to see that the header is added only for persisted XML requests. - */ - @SmallTest - @Feature({"Omaha"}) - public void testHTTPHeaderForPersistedXMLRequest() { - final String xml = "<lorem ipsum=\"dolor\" />"; - final long requestTimestamp = 0; - final long currentTimestamp = 11684; - final long currentTimestampInSeconds = currentTimestamp / 1000; - - mOmahaClient.registerNewRequest(requestTimestamp); - - assertTrue("Should default to sending install event.", mOmahaClient.isSendInstallEvent()); - assertEquals("Shouldn't have any failed attempts.", 0, - mOmahaClient.getCumulativeFailedAttempts()); - - MockConnection connection = null; - try { - mOmahaClient.postRequest(currentTimestamp, xml); - connection = mOmahaClient.getLastConnection(); - } catch (RequestFailureException e) { - fail(); - } - assertEquals("Age property field was unexpectedly added.", null, - connection.getRequestPropertyField()); - assertEquals("Age property value was unexpectedly set.", null, - connection.getRequestPropertyValue()); - - // Fail once, then check that the header is added. - mOmahaClient.getBackoffScheduler().increaseFailedAttempts(); - try { - mOmahaClient.postRequest(currentTimestamp, xml); - connection = mOmahaClient.getLastConnection(); - } catch (RequestFailureException e) { - fail(); - } - assertEquals("Age property field was not added.", "X-RequestAge", - connection.getRequestPropertyField()); - assertEquals("Age property value was incorrectly set.", currentTimestampInSeconds, - Long.parseLong(connection.getRequestPropertyValue())); - - // Make sure the header isn't added if we're not sending an install ping. - mOmahaClient.setSendInstallEvent(false); - mOmahaClient.registerNewRequest(requestTimestamp); - mOmahaClient.getBackoffScheduler().increaseFailedAttempts(); - try { - mOmahaClient.postRequest(currentTimestamp, xml); - connection = mOmahaClient.getLastConnection(); - } catch (RequestFailureException e) { - fail(); - } - assertEquals("Age property field was unexpectedly added.", null, - connection.getRequestPropertyField()); - assertEquals("Age property value was unexpectedly set.", null, - connection.getRequestPropertyValue()); - } - - @SmallTest - @Feature({"Omaha"}) - public void testInstallSource() { - HookedOmahaClient organicClient = new HookedOmahaClient(mContext, DeviceType.TABLET, - ServerResponse.SUCCESS, ConnectionStatus.RESPONDS, false); - String organicInstallSource = organicClient.determineInstallSource(); - assertEquals("Install source should have been treated as organic.", - OmahaClient.INSTALL_SOURCE_ORGANIC, organicInstallSource); - - HookedOmahaClient systemImageClient = new HookedOmahaClient(mContext, DeviceType.TABLET, - ServerResponse.SUCCESS, ConnectionStatus.RESPONDS, true); - String systemImageInstallSource = systemImageClient.determineInstallSource(); - assertEquals("Install source should have been treated as system image.", - OmahaClient.INSTALL_SOURCE_SYSTEM, systemImageInstallSource); - } - - /** - * OmahaClient that overrides simple methods for testing. - */ - private static class HookedOmahaClient extends OmahaClient { private final boolean mIsOnTablet; - private final boolean mSendValidResponse; private final boolean mIsInForeground; - private final boolean mConnectionTimesOut; - private final boolean mInstalledOnSystemImage; + private final boolean mIsInSystemImage; + private final MockExponentialBackoffScheduler mMockScheduler; + private MockRequestGenerator mMockGenerator; - private MockExponentialBackoffScheduler mMockScheduler; - private RequestGenerator mMockGenerator; - private final LinkedList<MockConnection> mMockConnections; - - private boolean mRequestAlarmWasSet; private int mNumUUIDsGenerated; - private int mPostResult = -1; + private long mNextScheduledTimestamp = -1; - public static HookedOmahaClient create(Context context) { - HookedOmahaClient omahaClient = new HookedOmahaClient(context, DeviceType.TABLET, - ServerResponse.SUCCESS, ConnectionStatus.RESPONDS, false); - omahaClient.onCreate(); - omahaClient.restoreState(context); - return omahaClient; + private boolean mInstallEventWasSent; + private TimestampPair mTimestampsOnRegisterNewRequest; + private TimestampPair mTimestampsOnSaveState; + + MockOmahaDelegate(Context context, DeviceType deviceType, InstallSource installSource) { + super(context); + mIsOnTablet = deviceType == DeviceType.TABLET; + mIsInForeground = true; + mIsInSystemImage = installSource == InstallSource.SYSTEM_IMAGE; + + mMockScheduler = new MockExponentialBackoffScheduler(OmahaBase.PREF_PACKAGE, context, + OmahaClient.MS_POST_BASE_DELAY, OmahaClient.MS_POST_MAX_DELAY); } - public HookedOmahaClient(Context context, DeviceType deviceType, - ServerResponse serverResponse, ConnectionStatus connectionStatus, - boolean installedOnSystemImage) { - attachBaseContext(context); - mIsOnTablet = deviceType == DeviceType.TABLET; - mSendValidResponse = serverResponse == ServerResponse.SUCCESS; - mIsInForeground = true; - mConnectionTimesOut = connectionStatus == ConnectionStatus.TIMES_OUT; - mMockConnections = new LinkedList<MockConnection>(); - mInstalledOnSystemImage = installedOnSystemImage; + @Override + protected RequestGenerator createRequestGenerator(Context context) { + mMockGenerator = new MockRequestGenerator( + context, mIsOnTablet ? DeviceType.TABLET : DeviceType.HANDSET); + return mMockGenerator; + } + + @Override + public boolean isInSystemImage() { + return mIsInSystemImage; + } + + @Override + MockExponentialBackoffScheduler getScheduler() { + return mMockScheduler; + } + + @Override + protected String generateUUID() { + mNumUUIDsGenerated += 1; + return "UUID" + mNumUUIDsGenerated; } @Override @@ -505,25 +101,85 @@ } @Override - public int getApplicationFlags() { - return mInstalledOnSystemImage ? ApplicationInfo.FLAG_SYSTEM : 0; + void scheduleService(Service service, long nextTimestamp) { + mNextScheduledTimestamp = nextTimestamp; } @Override - protected int handlePostRequest() { - mPostResult = super.handlePostRequest(); - return mPostResult; + void onHandlePostRequestDone(int result, boolean installEventWasSent) { + mPostResults.add(result); + mInstallEventWasSent = installEventWasSent; } - /** - * Checks if an alarm was set by the backoff scheduler. - */ - public boolean getPOSTAlarmWasSet() { - return mMockScheduler.getAlarmWasSet(); + @Override + void onRegisterNewRequestDone(long nextRequestTimestamp, long nextPostTimestamp) { + mTimestampsOnRegisterNewRequest = + new TimestampPair(nextRequestTimestamp, nextPostTimestamp); } - public boolean getRequestAlarmWasSet() { - return mRequestAlarmWasSet; + @Override + void onGenerateAndPostRequestDone(boolean result) { + mGenerateAndPostRequestResults.add(result); + } + + @Override + void onSaveStateDone(long nextRequestTimestamp, long nextPostTimestamp) { + mTimestampsOnSaveState = new TimestampPair(nextRequestTimestamp, nextPostTimestamp); + } + } + + private enum InstallSource { SYSTEM_IMAGE, ORGANIC } + private enum ServerResponse { SUCCESS, FAILURE } + private enum ConnectionStatus { RESPONDS, TIMES_OUT } + private enum InstallEvent { SEND, DONT_SEND } + private enum PostStatus { DUE, NOT_DUE } + + private AdvancedMockContext mContext; + private MockOmahaDelegate mDelegate; + private MockOmahaClient mOmahaClient; + + private MockOmahaClient createOmahaClient() { + return createOmahaClient( + ServerResponse.SUCCESS, ConnectionStatus.RESPONDS, DeviceType.HANDSET); + } + + private MockOmahaClient createOmahaClient( + ServerResponse response, ConnectionStatus status, DeviceType deviceType) { + MockOmahaClient omahaClient = new MockOmahaClient(mContext, response, status, deviceType); + omahaClient.onCreate(); + omahaClient.restoreState(mContext); + return omahaClient; + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + Context targetContext = getInstrumentation().getTargetContext(); + OmahaBase.setIsDisabledForTesting(false); + mContext = new AdvancedMockContext(targetContext); + } + + @Override + public void tearDown() throws Exception { + OmahaBase.setIsDisabledForTesting(true); + super.tearDown(); + } + + private class MockOmahaClient extends OmahaClient { + private final LinkedList<MockConnection> mMockConnections = new LinkedList<>(); + + private final boolean mSendValidResponse; + private final boolean mConnectionTimesOut; + private final boolean mIsOnTablet; + + public MockOmahaClient(Context context, ServerResponse serverResponse, + ConnectionStatus connectionStatus, DeviceType deviceType) { + attachBaseContext(context); + setDelegateForTests(mDelegate); + + mSendValidResponse = serverResponse == ServerResponse.SUCCESS; + mConnectionTimesOut = connectionStatus == ConnectionStatus.TIMES_OUT; + mIsOnTablet = deviceType == DeviceType.TABLET; } /** @@ -555,29 +211,11 @@ mSendInstallEvent = state; } - /** - * Mocks out the scheduler so that no alarms are really created. - */ - @Override - ExponentialBackoffScheduler createBackoffScheduler( - String prefPackage, Context context, long base, long max) { - mMockScheduler = - new MockExponentialBackoffScheduler(prefPackage, context, base, max); - return mMockScheduler; - } - - @Override - RequestGenerator createRequestGenerator(Context context) { - mMockGenerator = new MockRequestGenerator( - context, mIsOnTablet ? DeviceType.TABLET : DeviceType.HANDSET); - return mMockGenerator; - } - @Override protected HttpURLConnection createConnection() throws RequestFailureException { MockConnection connection = null; try { - URL url = new URL(getRequestGenerator().getServerUrl()); + URL url = new URL(mDelegate.getRequestGenerator().getServerUrl()); connection = new MockConnection(url, mIsOnTablet, mSendValidResponse, mSendInstallEvent, mConnectionTimesOut); mMockConnections.addLast(connection); @@ -586,19 +224,314 @@ } return connection; } - - @Override - protected void setAlarm(AlarmManager am, PendingIntent operation, long triggerAtTime) { - mRequestAlarmWasSet = true; - } - - @Override - protected String generateRandomUUID() { - mNumUUIDsGenerated += 1; - return "UUID" + mNumUUIDsGenerated; - } } + @SmallTest + @Feature({"Omaha"}) + public void testPipelineFreshInstall() { + final long now = 11684; + + mDelegate = new MockOmahaDelegate(mContext, DeviceType.HANDSET, InstallSource.ORGANIC); + mDelegate.getScheduler().setCurrentTime(now); + + // Trigger Omaha. + mOmahaClient = createOmahaClient(); + mOmahaClient.run(); + + // A fresh install results in two requests to the Omaha server: one for the install request + // and one for the ping request. + assertTrue(mDelegate.mInstallEventWasSent); + assertEquals(1, mDelegate.mPostResults.size()); + assertEquals(OmahaClient.POST_RESULT_SENT, mDelegate.mPostResults.get(0).intValue()); + assertEquals(2, mDelegate.mGenerateAndPostRequestResults.size()); + assertTrue(mDelegate.mGenerateAndPostRequestResults.get(0)); + assertTrue(mDelegate.mGenerateAndPostRequestResults.get(1)); + + // Successful requests mean that the next scheduled event should be checking for when the + // user is active. + assertEquals(now + OmahaClient.MS_BETWEEN_REQUESTS, mDelegate.mNextScheduledTimestamp); + checkTimestamps(now + OmahaClient.MS_BETWEEN_REQUESTS, now + OmahaClient.MS_POST_BASE_DELAY, + mDelegate.mTimestampsOnSaveState); + } + + @SmallTest + @Feature({"Omaha"}) + public void testPipelineRegularPing() { + final long now = 11684; + + mDelegate = new MockOmahaDelegate(mContext, DeviceType.HANDSET, InstallSource.ORGANIC); + mDelegate.getScheduler().setCurrentTime(now); + + // Record that an install event has already been sent and that we're due for a new request. + SharedPreferences.Editor editor = OmahaBase.getSharedPreferences(mContext).edit(); + editor.putBoolean(OmahaBase.PREF_SEND_INSTALL_EVENT, false); + editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEW_REQUEST, now); + editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEXT_POST_ATTEMPT, now); + editor.apply(); + + // Trigger Omaha. + mOmahaClient = createOmahaClient(); + mOmahaClient.run(); + + // Only the regular ping should have been sent. + assertFalse(mDelegate.mInstallEventWasSent); + assertEquals(1, mDelegate.mPostResults.size()); + assertEquals(OmahaClient.POST_RESULT_SENT, mDelegate.mPostResults.get(0).intValue()); + assertEquals(1, mDelegate.mGenerateAndPostRequestResults.size()); + assertTrue(mDelegate.mGenerateAndPostRequestResults.get(0)); + + // Successful requests mean that the next scheduled event should be checking for when the + // user is active. + assertEquals(now + OmahaClient.MS_BETWEEN_REQUESTS, mDelegate.mNextScheduledTimestamp); + checkTimestamps(now + OmahaClient.MS_BETWEEN_REQUESTS, now + OmahaClient.MS_POST_BASE_DELAY, + mDelegate.mTimestampsOnSaveState); + } + + @SmallTest + @Feature({"Omaha"}) + public void testTooEarlyToPing() { + final long now = 0; + final long later = 10000; + + mDelegate = new MockOmahaDelegate(mContext, DeviceType.HANDSET, InstallSource.ORGANIC); + mDelegate.getScheduler().setCurrentTime(now); + + // Put the time for the next request in the future. + SharedPreferences prefs = OmahaBase.getSharedPreferences(mContext); + prefs.edit().putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEW_REQUEST, later).apply(); + + // Trigger Omaha. + mOmahaClient = createOmahaClient(); + mOmahaClient.run(); + + // Nothing should have been POSTed. + assertEquals(0, mDelegate.mPostResults.size()); + assertEquals(0, mDelegate.mGenerateAndPostRequestResults.size()); + + // The next scheduled event is the request generation. Because there was nothing to POST, + // its timestamp should have remained unchanged and shouldn't have been considered when the + // new alarm was scheduled. + assertEquals(later, mDelegate.mNextScheduledTimestamp); + checkTimestamps(later, now, mDelegate.mTimestampsOnSaveState); + } + + @SmallTest + @Feature({"Omaha"}) + public void testTooEarlyToPostExistingRequest() { + final long timeGeneratedRequest = 0L; + final long now = 10000L; + final long timeSendNewPost = 20000L; + final long timeSendNewRequest = 50000L; + + mDelegate = new MockOmahaDelegate(mContext, DeviceType.HANDSET, InstallSource.ORGANIC); + mDelegate.getScheduler().setCurrentTime(now); + + SharedPreferences prefs = OmahaBase.getSharedPreferences(mContext); + SharedPreferences.Editor editor = prefs.edit(); + + // Make it so that a request was generated and is just waiting to be sent. + editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEW_REQUEST, timeSendNewRequest); + editor.putLong(OmahaBase.PREF_TIMESTAMP_OF_REQUEST, timeGeneratedRequest); + editor.putString(OmahaBase.PREF_PERSISTED_REQUEST_ID, "persisted_id"); + + // Put the time for the next post in the future. + editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEXT_POST_ATTEMPT, timeSendNewPost); + editor.apply(); + + // Trigger Omaha. + mOmahaClient = createOmahaClient(); + mOmahaClient.run(); + + // Request generation code should be skipped. + assertNull(mDelegate.mTimestampsOnRegisterNewRequest); + + // Should be too early to post, causing it to be rescheduled. + assertEquals(1, mDelegate.mPostResults.size()); + assertEquals(OmahaClient.POST_RESULT_SCHEDULED, mDelegate.mPostResults.get(0).intValue()); + assertEquals(0, mDelegate.mGenerateAndPostRequestResults.size()); + + // The next scheduled event is the POST. Because request generation code wasn't run, the + // timestamp for it shouldn't have changed. + assertEquals(timeSendNewPost, mDelegate.mNextScheduledTimestamp); + checkTimestamps(timeSendNewRequest, timeSendNewPost, mDelegate.mTimestampsOnSaveState); + } + + @SmallTest + @Feature({"Omaha"}) + public void testPostExistingRequestSuccessfully() { + final long timeGeneratedRequest = 0L; + final long now = 10000L; + final long timeSendNewPost = now; + final long timeRegisterNewRequest = 20000L; + + mDelegate = new MockOmahaDelegate(mContext, DeviceType.HANDSET, InstallSource.ORGANIC); + mDelegate.getScheduler().setCurrentTime(now); + + SharedPreferences prefs = OmahaBase.getSharedPreferences(mContext); + SharedPreferences.Editor editor = prefs.edit(); + + // Make it so that a regular <ping> was generated and is just waiting to be sent. + editor.putBoolean(OmahaBase.PREF_SEND_INSTALL_EVENT, false); + editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEW_REQUEST, timeRegisterNewRequest); + editor.putLong(OmahaBase.PREF_TIMESTAMP_OF_REQUEST, timeGeneratedRequest); + editor.putString(OmahaBase.PREF_PERSISTED_REQUEST_ID, "persisted_id"); + + // Send the POST now. + editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEXT_POST_ATTEMPT, timeSendNewPost); + editor.apply(); + + // Trigger Omaha. + mOmahaClient = createOmahaClient(); + mOmahaClient.run(); + + // Registering code shouldn't have fired. + assertNull(mDelegate.mTimestampsOnRegisterNewRequest); + + // Because we didn't send an install event, only one POST should have occurred. + assertEquals(1, mDelegate.mPostResults.size()); + assertEquals(OmahaClient.POST_RESULT_SENT, mDelegate.mPostResults.get(0).intValue()); + assertEquals(1, mDelegate.mGenerateAndPostRequestResults.size()); + assertTrue(mDelegate.mGenerateAndPostRequestResults.get(0)); + + // The next scheduled event is the request generation because there is nothing to POST. + // A successful POST adjusts all timestamps for the current time. + assertEquals(timeRegisterNewRequest, mDelegate.mNextScheduledTimestamp); + checkTimestamps(now + OmahaClient.MS_BETWEEN_REQUESTS, now + OmahaClient.MS_POST_BASE_DELAY, + mDelegate.mTimestampsOnSaveState); + } + + @SmallTest + @Feature({"Omaha"}) + public void testPostExistingButFails() { + final long timeGeneratedRequest = 0L; + final long now = 10000L; + final long timeSendNewPost = now; + final long timeRegisterNewRequest = timeGeneratedRequest + OmahaClient.MS_BETWEEN_REQUESTS; + + mDelegate = new MockOmahaDelegate(mContext, DeviceType.HANDSET, InstallSource.ORGANIC); + mDelegate.getScheduler().setCurrentTime(now); + + SharedPreferences prefs = OmahaBase.getSharedPreferences(mContext); + SharedPreferences.Editor editor = prefs.edit(); + + // Make it so that a regular <ping> was generated and is just waiting to be sent. + editor.putBoolean(OmahaBase.PREF_SEND_INSTALL_EVENT, false); + editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEW_REQUEST, timeRegisterNewRequest); + editor.putLong(OmahaBase.PREF_TIMESTAMP_OF_REQUEST, timeGeneratedRequest); + editor.putString(OmahaBase.PREF_PERSISTED_REQUEST_ID, "persisted_id"); + + // Send the POST now. + editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEXT_POST_ATTEMPT, timeSendNewPost); + editor.apply(); + + // Trigger Omaha. + mOmahaClient = createOmahaClient( + ServerResponse.FAILURE, ConnectionStatus.RESPONDS, DeviceType.HANDSET); + mOmahaClient.run(); + + // Registering code shouldn't have fired. + assertNull(mDelegate.mTimestampsOnRegisterNewRequest); + + // Because we didn't send an install event, only one POST should have occurred. + assertEquals(1, mDelegate.mPostResults.size()); + assertEquals(OmahaClient.POST_RESULT_FAILED, mDelegate.mPostResults.get(0).intValue()); + assertEquals(1, mDelegate.mGenerateAndPostRequestResults.size()); + assertFalse(mDelegate.mGenerateAndPostRequestResults.get(0)); + + // The next scheduled event should be the POST event, which is delayed by the base delay + // because no failures have happened yet. + assertEquals(mDelegate.mTimestampsOnSaveState.timestampNextPost, + mDelegate.mNextScheduledTimestamp); + checkTimestamps(timeRegisterNewRequest, now + OmahaClient.MS_POST_BASE_DELAY, + mDelegate.mTimestampsOnSaveState); + } + + @SmallTest + @Feature({"Omaha"}) + public void testTimestampWithinBounds() { + final long now = 0L; + final long timeRegisterNewRequest = OmahaClient.MS_BETWEEN_REQUESTS + 1; + + mDelegate = new MockOmahaDelegate(mContext, DeviceType.HANDSET, InstallSource.ORGANIC); + mDelegate.getScheduler().setCurrentTime(now); + + SharedPreferences prefs = OmahaBase.getSharedPreferences(mContext); + SharedPreferences.Editor editor = prefs.edit(); + + // Indicate that the next request should be generated way past an expected timeframe. + editor.putBoolean(OmahaBase.PREF_SEND_INSTALL_EVENT, false); + editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEW_REQUEST, timeRegisterNewRequest); + editor.apply(); + + // Trigger Omaha. + mOmahaClient = createOmahaClient(); + mOmahaClient.run(); + + // Request generation code should fire. + assertNotNull(mDelegate.mTimestampsOnRegisterNewRequest); + + // Because we didn't send an install event, only one POST should have occurred. + assertEquals(1, mDelegate.mPostResults.size()); + assertEquals(OmahaClient.POST_RESULT_SENT, mDelegate.mPostResults.get(0).intValue()); + assertEquals(1, mDelegate.mGenerateAndPostRequestResults.size()); + assertTrue(mDelegate.mGenerateAndPostRequestResults.get(0)); + + // The next scheduled event should be the timestamp for a new request generation. + assertEquals(mDelegate.mTimestampsOnSaveState.timestampNextRequest, + mDelegate.mNextScheduledTimestamp); + checkTimestamps(now + OmahaClient.MS_BETWEEN_REQUESTS, now + OmahaClient.MS_POST_BASE_DELAY, + mDelegate.mTimestampsOnSaveState); + } + + @SmallTest + @Feature({"Omaha"}) + public void testOverdueRequestCausesNewRegistration() { + final long timeGeneratedRequest = 0L; + final long now = 10000L; + final long timeSendNewPost = now; + final long timeRegisterNewRequest = + timeGeneratedRequest + OmahaClient.MS_BETWEEN_REQUESTS * 5; + + mDelegate = new MockOmahaDelegate(mContext, DeviceType.HANDSET, InstallSource.ORGANIC); + mDelegate.getScheduler().setCurrentTime(now); + + // Record that a regular <ping> was generated, but not sent, then assign it an invalid + // timestamp and try to send it now. + SharedPreferences prefs = OmahaBase.getSharedPreferences(mContext); + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean(OmahaBase.PREF_SEND_INSTALL_EVENT, false); + editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEW_REQUEST, timeRegisterNewRequest); + editor.putLong(OmahaBase.PREF_TIMESTAMP_OF_REQUEST, timeGeneratedRequest); + editor.putString(OmahaBase.PREF_PERSISTED_REQUEST_ID, "persisted_id"); + editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEXT_POST_ATTEMPT, timeSendNewPost); + editor.apply(); + + // Trigger Omaha. + mOmahaClient = createOmahaClient(); + mOmahaClient.run(); + + // Registering code shouldn't have fired. + checkTimestamps(now + OmahaClient.MS_BETWEEN_REQUESTS, now, + mDelegate.mTimestampsOnRegisterNewRequest); + + // Because we didn't send an install event, only one POST should have occurred. + assertEquals(1, mDelegate.mPostResults.size()); + assertEquals(OmahaClient.POST_RESULT_SENT, mDelegate.mPostResults.get(0).intValue()); + assertEquals(1, mDelegate.mGenerateAndPostRequestResults.size()); + assertTrue(mDelegate.mGenerateAndPostRequestResults.get(0)); + + // The next scheduled event should be the registration event. + assertEquals(mDelegate.mTimestampsOnSaveState.timestampNextRequest, + mDelegate.mNextScheduledTimestamp); + checkTimestamps(now + OmahaClient.MS_BETWEEN_REQUESTS, now + OmahaClient.MS_POST_BASE_DELAY, + mDelegate.mTimestampsOnSaveState); + } + + private void checkTimestamps( + long expectedRequestTimestamp, long expectedPostTimestamp, TimestampPair timestamps) { + assertEquals(expectedRequestTimestamp, timestamps.timestampNextRequest); + assertEquals(expectedPostTimestamp, timestamps.timestampNextPost); + } /** * Simulates communication with the actual Omaha server.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java index d1a4650..6a4b475 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java
@@ -4,7 +4,6 @@ package org.chromium.chrome.browser.payments; -import android.content.Context; import android.support.test.filters.MediumTest; import org.chromium.base.test.util.Feature; @@ -35,15 +34,14 @@ /** * Installs a mock service worker based payment app for testing. * - * @param optionPresence Whether the manifest has any payment options. Either NO_OPTIONS - * ONE_OPTION or TWO_OPTIONS + * @param instrumentPresence Whether the manifest has any payment options. Either NO_OPTIONS + * ONE_OPTION or TWO_OPTIONS */ private void installMockServiceWorkerPaymentApp(final int instrumentPresence) { PaymentAppFactory.getInstance().addAdditionalFactory( new PaymentAppFactory.PaymentAppFactoryAddition() { @Override - public void create(Context context, WebContents webContents, - Set<String> methodNames, + public void create(WebContents webContents, Set<String> methodNames, PaymentAppFactory.PaymentAppCreatedCallback callback) { ServiceWorkerPaymentAppBridge.Manifest testManifest = new ServiceWorkerPaymentAppBridge.Manifest();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java index 5bfd136..b50f1bc 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java
@@ -6,7 +6,6 @@ import static java.util.Arrays.asList; -import android.content.Context; import android.os.Handler; import android.view.View; import android.view.ViewGroup; @@ -805,7 +804,7 @@ /** * Called when the UI is ready for input. * - * @param ui The UI that is ready for input. + * @param target The UI that is ready for input. */ public void notifyCalled(T target) { ThreadUtils.assertOnUiThread(); @@ -865,7 +864,7 @@ final TestPay app = new TestPay(methodNames, instrumentPresence, responseSpeed); PaymentAppFactory.getInstance().addAdditionalFactory(new PaymentAppFactoryAddition() { @Override - public void create(Context context, WebContents webContents, Set<String> methodNames, + public void create(WebContents webContents, Set<String> methodNames, final PaymentAppFactory.PaymentAppCreatedCallback callback) { if (creationSpeed == IMMEDIATE_CREATION) { callback.onPaymentAppCreated(app);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java index 7f35cbd..99619b9 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
@@ -10,7 +10,7 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import static org.mockito.Mockito.anyString; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; @@ -50,8 +50,8 @@ import org.chromium.base.ContextUtils; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.DisableHistogramsRule; -import org.chromium.chrome.browser.EnableFeatures; import org.chromium.chrome.browser.ntp.ContextMenuManager; import org.chromium.chrome.browser.ntp.NewTabPage.DestructionObserver; import org.chromium.chrome.browser.ntp.cards.ContentSuggestionsTestUtils.CategoryInfoBuilder; @@ -82,8 +82,6 @@ @Config(manifest = Config.NONE) public class NewTabPageAdapterTest { @Rule - public EnableFeatures.Processor mEnableFeatureProcessor = new EnableFeatures.Processor(); - @Rule public DisableHistogramsRule mDisableHistogramsRule = new DisableHistogramsRule(); private FakeSuggestionsSource mSource; @@ -194,6 +192,8 @@ // Set empty variation params for the test. CardsVariationParameters.setTestVariationParams(new HashMap<String, String>()); + ChromeFeatureList.setTestEnabledFeatures(Collections.<String>emptySet()); + // Initialise the sign in state. We will be signed in by default in the tests. assertFalse(ChromePreferenceManager.getInstance(RuntimeEnvironment.application) .getNewTabPageSigninPromoDismissed()); @@ -216,6 +216,8 @@ @After public void tearDown() { + CardsVariationParameters.setTestVariationParams(null); + ChromeFeatureList.setTestEnabledFeatures(null); SigninManager.setInstanceForTesting(null); ChromePreferenceManager.getInstance(RuntimeEnvironment.application) .setNewTabPageSigninPromoDismissed(false);
diff --git a/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkValidator.java b/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkValidator.java index 377494bd..bb1e2ec3 100644 --- a/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkValidator.java +++ b/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkValidator.java
@@ -69,7 +69,6 @@ public static String findWebApkPackage(Context context, List<ResolveInfo> infos) { for (ResolveInfo info : infos) { if (info.activityInfo != null - && info.activityInfo.packageName.startsWith(WEBAPK_PACKAGE_PREFIX) && isValidWebApk(context, info.activityInfo.packageName)) { return info.activityInfo.packageName; } @@ -83,11 +82,14 @@ * @param webappPackageName The package name to check * @return true iff the WebAPK is installed and passes security checks */ - private static boolean isValidWebApk(Context context, String webappPackageName) { + public static boolean isValidWebApk(Context context, String webappPackageName) { if (sExpectedSignature == null) { Log.wtf(TAG, "WebApk validation failure - expected signature not set." + "missing call to WebApkValidator.initWithBrowserHostSignature"); } + if (!webappPackageName.startsWith(WEBAPK_PACKAGE_PREFIX)) { + return false; + } // check signature PackageInfo packageInfo = null; try {
diff --git a/chrome/app/android/chrome_jni_onload.cc b/chrome/app/android/chrome_jni_onload.cc index 1b703f4..64310dc 100644 --- a/chrome/app/android/chrome_jni_onload.cc +++ b/chrome/app/android/chrome_jni_onload.cc
@@ -4,17 +4,18 @@ #include "chrome/app/android/chrome_jni_onload.h" +#include "base/android/jni_android.h" #include "base/android/library_loader/library_loader_hooks.h" -#include "base/bind.h" #include "chrome/app/android/chrome_android_initializer.h" #include "chrome/browser/android/chrome_jni_registrar.h" #include "content/public/app/content_jni_onload.h" namespace android { -namespace { +bool OnJNIOnLoadRegisterJNI(JNIEnv* env) { + if (!content::android::OnJNIOnLoadRegisterJNI(env)) + return false; -bool RegisterJNI(JNIEnv* env) { if (base::android::GetLibraryProcessType(env) == base::android::PROCESS_BROWSER) { return RegisterBrowserJNI(env); @@ -22,26 +23,11 @@ return true; } -bool Init() { +bool OnJNIOnLoadInit() { + if (!content::android::OnJNIOnLoadInit()) + return false; + return RunChrome(); } -} // namespace - -bool OnJNIOnLoadRegisterJNI( - JavaVM* vm, - base::android::RegisterCallback callback) { - std::vector<base::android::RegisterCallback> register_callbacks; - register_callbacks.push_back(callback); - register_callbacks.push_back(base::Bind(&RegisterJNI)); - return content::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks); -} - -bool OnJNIOnLoadInit(base::android::InitCallback callback) { - std::vector<base::android::InitCallback> init_callbacks; - init_callbacks.push_back(callback); - init_callbacks.push_back(base::Bind(&Init)); - return content::android::OnJNIOnLoadInit(init_callbacks); -} - } // namespace android
diff --git a/chrome/app/android/chrome_jni_onload.h b/chrome/app/android/chrome_jni_onload.h index d5cb6ad9..efa9a8d 100644 --- a/chrome/app/android/chrome_jni_onload.h +++ b/chrome/app/android/chrome_jni_onload.h
@@ -9,11 +9,9 @@ namespace android { -bool OnJNIOnLoadRegisterJNI( - JavaVM* vm, - base::android::RegisterCallback callback); +bool OnJNIOnLoadRegisterJNI(JNIEnv* env); -bool OnJNIOnLoadInit(base::android::InitCallback callback); +bool OnJNIOnLoadInit(); } // namespace android
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index 87ac87bf..59912e9 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -3543,9 +3543,12 @@ <ph name="BEGIN_BOLD"><strong></ph>Note:<ph name="END_BOLD"></strong></ph> Only enable if you know what you are doing or if you have been asked to do so, as collection of data may reduce performance. </message> - <message name="IDS_EULA_BACK_BUTTON" desc="Back button shown on EULA screen."> + <message name="IDS_EULA_BACK_BUTTON" desc="Back button shown on EULA/OOBE screens."> Back </message> + <message name="IDS_EULA_NEXT_BUTTON" desc="Next button shown on EULA/OOBE screens."> + Next + </message> <message name="IDS_EULA_ACCEPT_AND_CONTINUE_BUTTON" desc="Accept button text below EULA terms of service"> Accept and continue </message>
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index fa2d0fd9..18a4170 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -8314,6 +8314,9 @@ Protected content exceptions </message> </if> + <message name="IDS_PROTECTED_CONTENT_ENABLE_CHECKBOX" desc="The label of the checkbox for enabling protected content."> + Allow sites to play protected content (recommended) + </message> <message name="IDS_PPAPI_BROKER_TAB_LABEL" desc="Label for PPAPI broker tab on Content Settings dialog"> Unsandboxed plugin access </message> @@ -15152,6 +15155,12 @@ <message name="IDS_FLAGS_ENABLE_NTP_SUGGESTIONS_NOTIFICATIONS_DESCRIPTION" desc="Description for the flag to enable notifications for content suggestions on the New Tab page." translateable="false"> If enabled, notifications will inform about new content suggestions on the New Tab page (see #enable-ntp-snippets). </message> + <message name="IDS_FLAGS_NTP_CONDENSED_LAYOUT_NAME" desc="Name for the flag to enable the condensed New Tab Page layout." translateable="false"> + Condensed NTP layout + </message> + <message name="IDS_FLAGS_NTP_CONDENSED_LAYOUT_DESCRIPTION" desc="Description for the flag to enable the condensed New Tab Page layout." translateable="false"> + Show a condensed layout on the New Tab Page. + </message> </if> <if expr="is_android">
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index 16454df..5c1a995 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -1603,7 +1603,7 @@ Reset </message> <message name="IDS_SETTINGS_RESET_VIEW_REPORTED_SETTINGS" desc="Label of a link that when clicked displays the settings that will be reported to Google for analysis."> - View reported settings + View report settings </message> <!-- Search Page --> @@ -1754,7 +1754,7 @@ Some content services use unique identifiers for the purposes of authorizing access to protected content. </message> <message name="IDS_SETTINGS_SITE_SETTINGS_PROTECTED_CONTENT_ENABLE" desc="Label for the toggle enabling protected content."> - Allow identifiers for protected content (computer restart may be required) + Allow sites to play protected content (recommended) </message> <message name="IDS_SETTINGS_SITE_SETTINGS_UNSANDBOXED_PLUGINS" desc="Label for the unsandboxed plugin access site settings."> Unsandboxed plugin access @@ -2720,10 +2720,10 @@ Off </message> <message name="IDS_SETTINGS_DISPLAY_TOUCH_CALIBRATION_TITLE" desc="In Device Settings > Displays, the label for initiating touch calibration."> - Calibrate + Calibrate touchscreen </message> <message name="IDS_SETTINGS_DISPLAY_TOUCH_CALIBRATION_TEXT" desc="In Device Settings > Displays, the sublabel for initiating touch calibration."> - Define the boundaries of your touchscreen over the display + Set up and adjust the accuracy of your touchscreen </message> <!-- Storage -->
diff --git a/chrome/app/vector_icons/BUILD.gn b/chrome/app/vector_icons/BUILD.gn index 9561cbd..d0e72c03 100644 --- a/chrome/app/vector_icons/BUILD.gn +++ b/chrome/app/vector_icons/BUILD.gn
@@ -2,10 +2,10 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -action("aggregate_vector_icons") { - visibility = [ ":*" ] +import("//ui/vector_icons/vector_icons.gni") - script = "//ui/gfx/vector_icons/aggregate_vector_icons.py" +aggregate_vector_icons("chrome_vector_icons") { + icon_directory = "." icons = [ "autologin.icon", @@ -61,36 +61,14 @@ "zoom_minus.icon", "zoom_plus.icon", ] - - output_cc = "$target_gen_dir/vector_icons.cc" - output_h = "$target_gen_dir/vector_icons.h" - - inputs = icons - inputs += [ - "vector_icons.cc.template", - "vector_icons.h.template", - ] - outputs = [ - output_cc, - output_h, - ] - - response_file_contents = rebase_path(icons, root_build_dir) - - args = [ - "--working_directory=" + rebase_path("./"), - "--file_list={{response_file_name}}", - "--output_cc=" + rebase_path(output_cc, root_build_dir), - "--output_h=" + rebase_path(output_h, root_build_dir), - ] } source_set("vector_icons") { - sources = get_target_outputs(":aggregate_vector_icons") + sources = get_target_outputs(":chrome_vector_icons") sources += [ "//ui/gfx/vector_icon_types.h" ] deps = [ - ":aggregate_vector_icons", + ":chrome_vector_icons", "//base", "//skia", ]
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index d9dc545..e8fbac0b 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -1378,6 +1378,7 @@ "//chrome/browser/metrics/variations:chrome_ui_string_overrider_factory", "//chrome/browser/net:probe_message_proto", "//chrome/browser/resources:component_extension_resources", + "//chrome/browser/ssl:proto", "//chrome/browser/ui", "//chrome/common/net", "//chrome/installer/util:with_no_strings", @@ -2870,6 +2871,8 @@ "android/webapk/chrome_webapk_host.h", "android/webapk/webapk_icon_hasher.cc", "android/webapk/webapk_icon_hasher.h", + "android/webapk/webapk_info.cc", + "android/webapk/webapk_info.h", "android/webapk/webapk_install_service.cc", "android/webapk/webapk_install_service.h", "android/webapk/webapk_install_service_factory.cc",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS index a7c968fd..e10a03f 100644 --- a/chrome/browser/DEPS +++ b/chrome/browser/DEPS
@@ -94,6 +94,7 @@ # No inclusion of WebKit from the browser, other than strictly enum/POD, # header-only types, and some selected common code. "-third_party/WebKit", + "+third_party/WebKit/public/platform/WebCache.h", "+third_party/WebKit/public/platform/WebDisplayMode.h", "+third_party/WebKit/public/platform/WebLoadingBehaviorFlag.h", "+third_party/WebKit/public/platform/WebGestureEvent.h", @@ -113,7 +114,6 @@ "+third_party/WebKit/public/platform/modules/webshare/webshare.mojom.h", "+third_party/WebKit/public/platform/site_engagement.mojom.h", "+third_party/WebKit/public/public_features.h", - "+third_party/WebKit/public/web/WebCache.h", "+third_party/WebKit/public/web/WebContextMenuData.h", "+third_party/WebKit/public/web/WebFindOptions.h", "+third_party/WebKit/public/web/WebMediaPlayerAction.h",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 31f3104..898ab82e 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -1884,6 +1884,9 @@ kContentSuggestionsNotificationsFeature, kContentSuggestionsNotificationsFeatureVariations, ntp_snippets::kStudyName)}, + {"ntp-condensed-layout", IDS_FLAGS_NTP_CONDENSED_LAYOUT_NAME, + IDS_FLAGS_NTP_CONDENSED_LAYOUT_DESCRIPTION, kOsAndroid, + FEATURE_VALUE_TYPE(chrome::android::kNTPCondensedLayoutFeature)}, #endif // OS_ANDROID #if BUILDFLAG(ENABLE_WEBRTC) && BUILDFLAG(RTC_USE_H264) && \ !defined(MEDIA_DISABLE_FFMPEG) @@ -2155,7 +2158,7 @@ "AutofillCreditCardPopupLayout")}, {"native-android-history-manager", IDS_NATIVE_ANDROID_HISTORY_MANAGER, IDS_NATIVE_ANDROID_HISTORY_MANAGER_DESCRIPTION, kOsAndroid, - FEATURE_VALUE_TYPE(chrome::android::kNativeAndroidHistoryManager)}, + FEATURE_VALUE_TYPE(features::kNativeAndroidHistoryManager)}, #endif // OS_ANDROID #if defined(OS_WIN)
diff --git a/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc b/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc index 090e1f2..fdd258f 100644 --- a/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc +++ b/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
@@ -54,7 +54,7 @@ std::unique_ptr<SkBitmap> icon, int event_request_id, webapk::InstallSource webapk_install_source) { - bool is_webapk = ChromeWebApkHost::AreWebApkEnabled(); + bool is_webapk = ChromeWebApkHost::CanInstallWebApk(); std::string webapk_package_name = ""; const GURL& url = shortcut_info->url; if (is_webapk)
diff --git a/chrome/browser/android/banners/app_banner_manager_android.cc b/chrome/browser/android/banners/app_banner_manager_android.cc index 9a267231..9d0bff1 100644 --- a/chrome/browser/android/banners/app_banner_manager_android.cc +++ b/chrome/browser/android/banners/app_banner_manager_android.cc
@@ -44,7 +44,7 @@ if (!manifest.IsEmpty()) { shortcut_info->UpdateFromManifest(manifest); shortcut_info->manifest_url = manifest_url; - shortcut_info->best_icon_url = icon_url; + shortcut_info->best_primary_icon_url = icon_url; shortcut_info->UpdateSource(ShortcutInfo::SOURCE_APP_BANNER); } return shortcut_info; @@ -172,7 +172,7 @@ Stop(); } - if (ChromeWebApkHost::AreWebApkEnabled()) { + if (ChromeWebApkHost::CanInstallWebApk()) { if (!AreWebManifestUrlsWebApkCompatible(manifest_)) { ReportStatus(web_contents(), URL_NOT_SUPPORTED_FOR_WEBAPK); Stop(); @@ -279,9 +279,9 @@ const bool correct_platform = (platform == "play"); if (correct_platform && !id.empty()) return true; - ReportStatus(web_contents(), - correct_platform ? NO_ID_SPECIFIED - : PLATFORM_NOT_SUPPORTED_ON_ANDROID); + ReportStatus( + web_contents(), + correct_platform ? NO_ID_SPECIFIED : PLATFORM_NOT_SUPPORTED_ON_ANDROID); return false; } @@ -306,7 +306,6 @@ return AppBannerSettingsHelper::GetHomescreenLanguageOption(); } - // static ScopedJavaLocalRef<jobject> GetJavaBannerManagerForWebContents( JNIEnv* env, @@ -314,8 +313,8 @@ const JavaParamRef<jobject>& java_web_contents) { AppBannerManagerAndroid* manager = AppBannerManagerAndroid::FromWebContents( content::WebContents::FromJavaWebContents(java_web_contents)); - return manager? ScopedJavaLocalRef<jobject>(manager->GetJavaBannerManager()) - : ScopedJavaLocalRef<jobject>(); + return manager ? ScopedJavaLocalRef<jobject>(manager->GetJavaBannerManager()) + : ScopedJavaLocalRef<jobject>(); } // static
diff --git a/chrome/browser/android/chrome_entry_point.cc b/chrome/browser/android/chrome_entry_point.cc index 4a540518..fad7aa7 100644 --- a/chrome/browser/android/chrome_entry_point.cc +++ b/chrome/browser/android/chrome_entry_point.cc
@@ -10,16 +10,8 @@ namespace { -bool RegisterJNI(JNIEnv* env) { - return true; -} - -bool Init() { - return true; -} - bool NativeInit() { - return android::OnJNIOnLoadInit(base::Bind(&Init)); + return android::OnJNIOnLoadInit(); } } // namespace @@ -35,7 +27,7 @@ base::android::SetJniRegistrationType( base::android::SELECTIVE_JNI_REGISTRATION); } - if (!android::OnJNIOnLoadRegisterJNI(vm, base::Bind(&RegisterJNI))) { + if (!android::OnJNIOnLoadRegisterJNI(env)) { return -1; } base::android::SetNativeInitializationHook(NativeInit);
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc index b2d6c90..5c03d74 100644 --- a/chrome/browser/android/chrome_feature_list.cc +++ b/chrome/browser/android/chrome_feature_list.cc
@@ -35,6 +35,7 @@ &autofill::kAutofillScanCardholderName, &features::kConsistentOmniboxGeolocation, &features::kCredentialManagementAPI, + &features::kNativeAndroidHistoryManager, &features::kServiceWorkerPaymentApps, &features::kSimplifiedFullscreenUI, &features::kVrShell, @@ -48,8 +49,8 @@ &kContextualSearchSingleActions, &kImportantSitesInCBD, &kImprovedA2HS, - &kNativeAndroidHistoryManager, &kNoCreditCardAbort, + &kNTPCondensedLayoutFeature, &kNTPFakeOmniboxTextFeature, &kNTPOfflinePagesFeature, &kNTPSuggestionsStandaloneUIFeature, @@ -106,15 +107,15 @@ const base::Feature kImprovedA2HS{"ImprovedA2HS", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kNativeAndroidHistoryManager{ - "AndroidHistoryManager", base::FEATURE_DISABLED_BY_DEFAULT}; - const base::Feature kNoCreditCardAbort{"NoCreditCardAbort", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kNTPFakeOmniboxTextFeature{ "NTPFakeOmniboxText", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kNTPCondensedLayoutFeature{ + "NTPCondensedLayout", base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kNTPOfflinePagesFeature{"NTPOfflinePages", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h index 47b5de4..1ff7a525c 100644 --- a/chrome/browser/android/chrome_feature_list.h +++ b/chrome/browser/android/chrome_feature_list.h
@@ -23,8 +23,8 @@ extern const base::Feature kDownloadAutoResumptionThrottling; extern const base::Feature kImportantSitesInCBD; extern const base::Feature kImprovedA2HS; -extern const base::Feature kNativeAndroidHistoryManager; extern const base::Feature kNoCreditCardAbort; +extern const base::Feature kNTPCondensedLayoutFeature; extern const base::Feature kNTPFakeOmniboxTextFeature; extern const base::Feature kNTPOfflinePagesFeature; extern const base::Feature kNTPSuggestionsStandaloneUIFeature;
diff --git a/chrome/browser/android/devtools_manager_delegate_android.cc b/chrome/browser/android/devtools_manager_delegate_android.cc index 10ec47a..96f58833 100644 --- a/chrome/browser/android/devtools_manager_delegate_android.cc +++ b/chrome/browser/android/devtools_manager_delegate_android.cc
@@ -112,6 +112,10 @@ return true; } + base::TimeTicks GetLastActivityTime() override { + return agent_host_ ? agent_host_->GetLastActivityTime() : base::TimeTicks(); + } + void SendMessageToBackend(const std::string& message) override { if (agent_host_) agent_host_->DispatchProtocolMessage(this, message);
diff --git a/chrome/browser/android/favicon_helper.cc b/chrome/browser/android/favicon_helper.cc index 6ac5e36..bfa8416 100644 --- a/chrome/browser/android/favicon_helper.cc +++ b/chrome/browser/android/favicon_helper.cc
@@ -173,9 +173,9 @@ // TODO(treib): Optimize this by creating a FaviconService::HasFavicon method // so that we don't have to actually get the image. ScopedJavaGlobalRef<jobject> j_scoped_callback(env, j_availability_callback); - favicon_base::FaviconImageCallback callback_runner = - base::Bind(&OnFaviconImageResultAvailable, j_scoped_callback, profile, - web_contents, page_url, icon_url, icon_type, j_is_temporary); + favicon_base::FaviconImageCallback callback_runner = base::Bind( + &FaviconHelper::OnFaviconImageResultAvailable, j_scoped_callback, profile, + web_contents, page_url, icon_url, icon_type, j_is_temporary); favicon::FaviconService* service = FaviconServiceFactory::GetForProfile( profile, ServiceAccessType::IMPLICIT_ACCESS); favicon::GetFaviconImageForPageURL(service, page_url, icon_type, @@ -249,10 +249,9 @@ JNIEnv* env = AttachCurrentThread(); Java_IconAvailabilityCallback_onIconAvailabilityChecked( - env, j_availability_callback, success); + env, j_availability_callback, /*newly_available=*/success); } - void FaviconHelper::OnFaviconImageResultAvailable( const ScopedJavaGlobalRef<jobject>& j_availability_callback, Profile* profile, @@ -263,17 +262,20 @@ bool is_temporary, const favicon_base::FaviconImageResult& result) { // If there already is a favicon, return immediately. - if (!result.image.IsEmpty()) { + // Can |web_contents| be null here? crbug.com/688249 + if (!result.image.IsEmpty() || !web_contents) { + // Either the image already exists in the FaviconService, or it doesn't and + // we can't download it. Either way, it's not *newly* available. JNIEnv* env = AttachCurrentThread(); Java_IconAvailabilityCallback_onIconAvailabilityChecked( - env, j_availability_callback, false); + env, j_availability_callback, /*newly_available=*/false); return; } web_contents->DownloadImage( icon_url, true, 0, false, - base::Bind(OnFaviconDownloaded, j_availability_callback, profile, - page_url, icon_type, is_temporary)); + base::Bind(&FaviconHelper::OnFaviconDownloaded, j_availability_callback, + profile, page_url, icon_type, is_temporary)); } bool FaviconHelper::RegisterFaviconHelper(JNIEnv* env) {
diff --git a/chrome/browser/android/monochrome_entry_point.cc b/chrome/browser/android/monochrome_entry_point.cc index 7a04309c..be2abcb 100644 --- a/chrome/browser/android/monochrome_entry_point.cc +++ b/chrome/browser/android/monochrome_entry_point.cc
@@ -10,10 +10,6 @@ namespace { -bool Init() { - return true; -} - bool NativeInit() { JNIEnv* env = base::android::AttachCurrentThread(); int library_process_type = base::android::GetLibraryProcessType(env); @@ -24,7 +20,7 @@ break; case base::android::PROCESS_BROWSER: case base::android::PROCESS_CHILD: - return android::OnJNIOnLoadInit(base::Bind(&Init)); + return android::OnJNIOnLoadInit(); break; default: NOTREACHED();
diff --git a/chrome/browser/android/ntp/content_suggestions_notifier_service.cc b/chrome/browser/android/ntp/content_suggestions_notifier_service.cc index 2de34db..bfc15e8 100644 --- a/chrome/browser/android/ntp/content_suggestions_notifier_service.cc +++ b/chrome/browser/android/ntp/content_suggestions_notifier_service.cc
@@ -92,12 +92,17 @@ base::Time timeout_at = suggestion->notification_extra() ? suggestion->notification_extra()->deadline : base::Time::Max(); + bool use_snippet = variations::GetVariationParamByFeatureAsBool( + kContentSuggestionsNotificationsFeature, + kContentSuggestionsNotificationsUseSnippetAsTextParam, false); service_->FetchSuggestionImage( suggestion->id(), base::Bind(&NotifyingObserver::ImageFetched, weak_ptr_factory_.GetWeakPtr(), suggestion->id(), suggestion->url(), suggestion->title(), - suggestion->publisher_name(), timeout_at)); + use_snippet ? suggestion->snippet_text() + : suggestion->publisher_name(), + timeout_at)); } void OnCategoryStatusChanged(Category category, @@ -174,7 +179,7 @@ void ImageFetched(const ContentSuggestion::ID& id, const GURL& url, const base::string16& title, - const base::string16& publisher, + const base::string16& text, base::Time timeout_at, const gfx::Image& image) { if (!ShouldNotifyInState(app_status_listener_.GetState())) { @@ -185,7 +190,7 @@ << image.Size().height() << " image for " << url.spec(); prefs_->ClearPref(kNotificationIDWithinCategory); if (ContentSuggestionsNotificationHelper::SendNotification( - id, url, title, publisher, CropSquare(image), timeout_at)) { + id, url, title, text, CropSquare(image), timeout_at)) { RecordContentSuggestionsNotificationImpression( id.category().IsKnownCategory(KnownCategories::ARTICLES) ? CONTENT_SUGGESTIONS_ARTICLE
diff --git a/chrome/browser/android/ntp/new_tab_page_url_handler.cc b/chrome/browser/android/ntp/new_tab_page_url_handler.cc index 4633522..38dc11c 100644 --- a/chrome/browser/android/ntp/new_tab_page_url_handler.cc +++ b/chrome/browser/android/ntp/new_tab_page_url_handler.cc
@@ -9,6 +9,7 @@ #include "base/strings/string_util.h" #include "chrome/browser/android/chrome_feature_list.h" #include "chrome/common/url_constants.h" +#include "content/public/common/content_features.h" #include "content/public/common/url_constants.h" #include "url/gurl.h" @@ -31,14 +32,13 @@ return true; } - // TODO(twellington): stop redirecting chrome://bookmarks to - // chrome-native://bookmarks when M57 is a distant memory. + // TODO(twellington): stop redirecting chrome://history to + // chrome-native://history when M57 is a distant memory. // See http://crbug.com/654071. - if (base::FeatureList::IsEnabled( - chrome::android::kNativeAndroidHistoryManager) && + if (base::FeatureList::IsEnabled(features::kNativeAndroidHistoryManager) && (url->host() == kChromeUIHistoryHost || url->host() == kChromeUIHistoryFrameHost)) { - *url = GURL(kChromeUINativeHistoryURL); + *url = GURL(content::kChromeUINativeHistoryURL); return true; }
diff --git a/chrome/browser/android/preferences/pref_service_bridge.cc b/chrome/browser/android/preferences/pref_service_bridge.cc index 06b54ef..b1faf28 100644 --- a/chrome/browser/android/preferences/pref_service_bridge.cc +++ b/chrome/browser/android/preferences/pref_service_bridge.cc
@@ -717,9 +717,11 @@ static void FetchImportantSites(JNIEnv* env, const JavaParamRef<jclass>& clazz, const JavaParamRef<jobject>& java_callback) { + Profile* profile = GetOriginalProfile(); std::vector<ImportantSitesUtil::ImportantDomainInfo> important_sites = - ImportantSitesUtil::GetImportantRegisterableDomains(GetOriginalProfile(), + ImportantSitesUtil::GetImportantRegisterableDomains(profile, kMaxImportantSites); + bool dialog_disabled = ImportantSitesUtil::IsDialogDisabled(profile); std::vector<std::string> important_domains; std::vector<int32_t> important_domain_reasons; @@ -739,7 +741,7 @@ Java_ImportantSitesCallback_onImportantRegisterableDomainsReady( env, java_callback.obj(), java_domains.obj(), java_origins.obj(), - java_reasons.obj()); + java_reasons.obj(), dialog_disabled); } // This value should not change during a sessions, as it's used for UMA metrics.
diff --git a/chrome/browser/android/shortcut_helper.cc b/chrome/browser/android/shortcut_helper.cc index d352271..dfa0aefc 100644 --- a/chrome/browser/android/shortcut_helper.cc +++ b/chrome/browser/android/shortcut_helper.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/android/shortcut_helper.h" #include <jni.h> +#include <utility> #include "base/android/jni_android.h" #include "base/android/jni_array.h" @@ -46,8 +47,7 @@ ScopedJavaLocalRef<jintArray> java_size_array = Java_ShortcutHelper_getHomeScreenIconAndSplashImageSizes(env); std::vector<int> sizes; - base::android::JavaIntArrayToIntVector( - env, java_size_array.obj(), &sizes); + base::android::JavaIntArrayToIntVector(env, java_size_array.obj(), &sizes); // Check that the size returned is what is expected. DCHECK(sizes.size() == 5); @@ -64,7 +64,7 @@ DCHECK(g_minimum_splash_image_size <= g_ideal_splash_image_size); } -} // anonymous namespace +} // anonymous namespace // static void ShortcutHelper::AddToLauncherWithSkBitmap( @@ -111,8 +111,9 @@ base::android::ConvertUTF16ToJavaString(env, info.name); ScopedJavaLocalRef<jstring> java_short_name = base::android::ConvertUTF16ToJavaString(env, info.short_name); - ScopedJavaLocalRef<jstring> java_best_icon_url = - base::android::ConvertUTF8ToJavaString(env, info.best_icon_url.spec()); + ScopedJavaLocalRef<jstring> java_best_primary_icon_url = + base::android::ConvertUTF8ToJavaString(env, + info.best_primary_icon_url.spec()); ScopedJavaLocalRef<jobject> java_bitmap; if (icon_bitmap.getSize()) java_bitmap = gfx::ConvertToJavaBitmap(&icon_bitmap); @@ -124,16 +125,15 @@ uintptr_t callback_pointer = reinterpret_cast<uintptr_t>(new base::Closure(splash_image_callback)); - Java_ShortcutHelper_addWebapp(env, java_webapp_id, java_url, java_scope_url, - java_user_title, java_name, java_short_name, - java_best_icon_url, java_bitmap, info.display, - info.orientation, info.source, info.theme_color, - info.background_color, callback_pointer); + Java_ShortcutHelper_addWebapp( + env, java_webapp_id, java_url, java_scope_url, java_user_title, java_name, + java_short_name, java_best_primary_icon_url, java_bitmap, info.display, + info.orientation, info.source, info.theme_color, info.background_color, + callback_pointer); } -void ShortcutHelper::AddShortcutWithSkBitmap( - const ShortcutInfo& info, - const SkBitmap& icon_bitmap) { +void ShortcutHelper::AddShortcutWithSkBitmap(const ShortcutInfo& info, + const SkBitmap& icon_bitmap) { JNIEnv* env = base::android::AttachCurrentThread(); ScopedJavaLocalRef<jstring> java_url = base::android::ConvertUTF8ToJavaString(env, info.url.spec()); @@ -198,9 +198,8 @@ } // static -void ShortcutHelper::StoreWebappSplashImage( - const std::string& webapp_id, - const SkBitmap& splash_image) { +void ShortcutHelper::StoreWebappSplashImage(const std::string& webapp_id, + const SkBitmap& splash_image) { if (splash_image.drawsNothing()) return; @@ -266,20 +265,19 @@ std::string webapk_package_name = ""; if (java_webapk_package_name.obj()) { - webapk_package_name = base::android::ConvertJavaStringToUTF8( - env, java_webapk_package_name); + webapk_package_name = + base::android::ConvertJavaStringToUTF8(env, java_webapk_package_name); } return webapk_package_name; } // static -bool ShortcutHelper::IsWebApkInstalled( - content::BrowserContext* browser_context, - const GURL& start_url, - const GURL& manifest_url) { +bool ShortcutHelper::IsWebApkInstalled(content::BrowserContext* browser_context, + const GURL& start_url, + const GURL& manifest_url) { return !QueryWebApkPackage(start_url).empty() || - WebApkInstallService::Get(browser_context) - ->IsInstallInProgress(manifest_url); + WebApkInstallService::Get(browser_context) + ->IsInstallInProgress(manifest_url); } GURL ShortcutHelper::GetScopeFromURL(const GURL& url) { @@ -291,6 +289,13 @@ return GURL(base::android::ConvertJavaStringToUTF16(env, java_scope_url)); } +void ShortcutHelper::RetrieveWebApks(const WebApkInfoCallback& callback) { + uintptr_t callback_pointer = + reinterpret_cast<uintptr_t>(new WebApkInfoCallback(callback)); + Java_ShortcutHelper_retrieveWebApks(base::android::AttachCurrentThread(), + callback_pointer); +} + // Callback used by Java when the shortcut has been created. // |splash_image_callback| is a pointer to a base::Closure allocated in // AddShortcutWithSkBitmap, so reinterpret_cast it back and run it. @@ -308,6 +313,44 @@ delete splash_image_callback; } +void OnWebApksRetrieved(JNIEnv* env, + const JavaParamRef<jclass>& clazz, + const jlong jcallback_pointer, + const JavaParamRef<jobjectArray>& jshort_names, + const JavaParamRef<jobjectArray>& jpackage_names, + const JavaParamRef<jintArray>& jshell_apk_versions, + const JavaParamRef<jintArray>& jversion_codes) { + DCHECK(jcallback_pointer); + std::vector<std::string> short_names; + base::android::AppendJavaStringArrayToStringVector(env, jshort_names, + &short_names); + std::vector<std::string> package_names; + base::android::AppendJavaStringArrayToStringVector(env, jpackage_names, + &package_names); + std::vector<int> shell_apk_versions; + base::android::JavaIntArrayToIntVector(env, jshell_apk_versions, + &shell_apk_versions); + std::vector<int> version_codes; + base::android::JavaIntArrayToIntVector(env, jversion_codes, &version_codes); + + DCHECK(short_names.size() == package_names.size()); + DCHECK(short_names.size() == shell_apk_versions.size()); + DCHECK(short_names.size() == version_codes.size()); + + std::vector<WebApkInfo> webapk_list; + webapk_list.reserve(short_names.size()); + for (size_t i = 0; i < short_names.size(); ++i) { + webapk_list.push_back(WebApkInfo(std::move(short_names[i]), + std::move(package_names[i]), + shell_apk_versions[i], version_codes[i])); + } + + ShortcutHelper::WebApkInfoCallback* webapk_list_callback = + reinterpret_cast<ShortcutHelper::WebApkInfoCallback*>(jcallback_pointer); + webapk_list_callback->Run(webapk_list); + delete webapk_list_callback; +} + bool ShortcutHelper::RegisterShortcutHelper(JNIEnv* env) { return RegisterNativesImpl(env); }
diff --git a/chrome/browser/android/shortcut_helper.h b/chrome/browser/android/shortcut_helper.h index 823ed082..26a3a10 100644 --- a/chrome/browser/android/shortcut_helper.h +++ b/chrome/browser/android/shortcut_helper.h
@@ -5,11 +5,15 @@ #ifndef CHROME_BROWSER_ANDROID_SHORTCUT_HELPER_H_ #define CHROME_BROWSER_ANDROID_SHORTCUT_HELPER_H_ +#include <string> +#include <vector> + #include "base/android/jni_android.h" #include "base/android/jni_weak_ref.h" #include "base/callback_forward.h" #include "base/macros.h" #include "chrome/browser/android/shortcut_info.h" +#include "chrome/browser/android/webapk/webapk_info.h" #include "chrome/browser/android/webapk/webapk_installer.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -22,6 +26,9 @@ // ShortcutHelper in Java. class ShortcutHelper { public: + using WebApkInfoCallback = + base::Callback<void(const std::vector<WebApkInfo>&)>; + // Registers JNI hooks. static bool RegisterShortcutHelper(JNIEnv* env); @@ -117,6 +124,10 @@ // when the Web Manifest does not specify a scope URL. static GURL GetScopeFromURL(const GURL& url); + // Fetches information on all the WebAPKs installed on the device and returns + // the info to the |callback|. + static void RetrieveWebApks(const WebApkInfoCallback& callback); + private: ShortcutHelper() = delete; ~ShortcutHelper() = delete;
diff --git a/chrome/browser/android/shortcut_info.h b/chrome/browser/android/shortcut_info.h index 50036fb..af89f082 100644 --- a/chrome/browser/android/shortcut_info.h +++ b/chrome/browser/android/shortcut_info.h
@@ -53,7 +53,7 @@ Source source; int64_t theme_color; int64_t background_color; - GURL best_icon_url; + GURL best_primary_icon_url; GURL best_badge_icon_url; std::vector<std::string> icon_urls; };
diff --git a/chrome/browser/android/vr_shell/OWNERS b/chrome/browser/android/vr_shell/OWNERS index 0b3ab0a..973d96a 100644 --- a/chrome/browser/android/vr_shell/OWNERS +++ b/chrome/browser/android/vr_shell/OWNERS
@@ -5,3 +5,5 @@ girard@chromium.org mthiesse@chromium.org cjgrant@chromium.org + +# COMPONENT: UI>Browser>VR
diff --git a/chrome/browser/android/webapk/chrome_webapk_host.cc b/chrome/browser/android/webapk/chrome_webapk_host.cc index 1ebfe489..ae712eea 100644 --- a/chrome/browser/android/webapk/chrome_webapk_host.cc +++ b/chrome/browser/android/webapk/chrome_webapk_host.cc
@@ -21,9 +21,9 @@ } // static -bool ChromeWebApkHost::AreWebApkEnabled() { +bool ChromeWebApkHost::CanInstallWebApk() { JNIEnv* env = base::android::AttachCurrentThread(); - return Java_ChromeWebApkHost_areWebApkEnabled(env); + return Java_ChromeWebApkHost_canInstallWebApk(env); } // static @@ -33,3 +33,12 @@ return variations::GetVariationParamValueByFeature( chrome::android::kImprovedA2HS, kPlayInstall) == "true"; } + +// static +jboolean CanInstallFromUnknownSources( + JNIEnv* env, + const base::android::JavaParamRef<jclass>& clazz) { + return base::FeatureList::GetInstance()->IsFeatureOverriddenFromCommandLine( + chrome::android::kImprovedA2HS.name, + base::FeatureList::OVERRIDE_ENABLE_FEATURE); +}
diff --git a/chrome/browser/android/webapk/chrome_webapk_host.h b/chrome/browser/android/webapk/chrome_webapk_host.h index dc84ea17..943e07e 100644 --- a/chrome/browser/android/webapk/chrome_webapk_host.h +++ b/chrome/browser/android/webapk/chrome_webapk_host.h
@@ -16,8 +16,9 @@ // Registers JNI hooks. static bool Register(JNIEnv* env); - // Returns whether the "enalbe-webapk" is turned on. - static bool AreWebApkEnabled(); + // Returns whether installing WebApk is possible either from "unknown sources" + // or Google Play. + static bool CanInstallWebApk(); private: DISALLOW_IMPLICIT_CONSTRUCTORS(ChromeWebApkHost);
diff --git a/chrome/browser/android/webapk/webapk_info.cc b/chrome/browser/android/webapk/webapk_info.cc new file mode 100644 index 0000000..d97a469a7 --- /dev/null +++ b/chrome/browser/android/webapk/webapk_info.cc
@@ -0,0 +1,16 @@ +// 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/android/webapk/webapk_info.h" + +WebApkInfo::WebApkInfo(std::string short_name, + std::string package_name, + int shell_apk_version, + int version_code) + : short_name(short_name), + package_name(package_name), + shell_apk_version(shell_apk_version), + version_code(version_code) {} + +WebApkInfo::~WebApkInfo() {}
diff --git a/chrome/browser/android/webapk/webapk_info.h b/chrome/browser/android/webapk/webapk_info.h new file mode 100644 index 0000000..746c5f51 --- /dev/null +++ b/chrome/browser/android/webapk/webapk_info.h
@@ -0,0 +1,44 @@ +// 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 CHROME_BROWSER_ANDROID_WEBAPK_WEBAPK_INFO_H_ +#define CHROME_BROWSER_ANDROID_WEBAPK_WEBAPK_INFO_H_ + +#include <string> + +#include "base/macros.h" + +// Structure with information about a WebAPK. +// +// This class is passed around in a std::vector to generate the chrome://webapks +// page. To reduce copying overhead, this class is move-only, and +// move-constructs its string arguments (which are copied from Java to C++ into +// a temporary prior to construction). +struct WebApkInfo { + WebApkInfo(std::string short_name, + std::string package_name, + int shell_apk_version, + int version_code); + ~WebApkInfo(); + + WebApkInfo& operator=(WebApkInfo&& other) = default; + WebApkInfo(WebApkInfo&& other) = default; + + // Short name of the WebAPK. + std::string short_name; + + // Package name of the WebAPK. + std::string package_name; + + // Shell APK version of the WebAPK. + int shell_apk_version; + + // Version code of the WebAPK. + int version_code; + + private: + DISALLOW_COPY_AND_ASSIGN(WebApkInfo); +}; + +#endif // CHROME_BROWSER_ANDROID_WEBAPK_WEBAPK_INFO_H_
diff --git a/chrome/browser/android/webapk/webapk_installer.cc b/chrome/browser/android/webapk/webapk_installer.cc index 161a388..685f190 100644 --- a/chrome/browser/android/webapk/webapk_installer.cc +++ b/chrome/browser/android/webapk/webapk_installer.cc
@@ -38,7 +38,8 @@ // The default WebAPK server URL. const char kDefaultServerUrl[] = - "https://webapk.googleapis.com/v1/webApks/?alt=proto&key=AIzaSyAoI6v-F31-3t9NunLYEiKcPIqgTJIUZBw"; + "https://webapk.googleapis.com/v1/webApks/" + "?alt=proto&key=AIzaSyAoI6v-F31-3t9NunLYEiKcPIqgTJIUZBw"; // The MIME type of the POST data sent to the server. const char kProtoMimeType[] = "application/x-protobuf"; @@ -67,9 +68,8 @@ // Returns the scope from |info| if it is specified. Otherwise, returns the // default scope. GURL GetScope(const ShortcutInfo& info) { - return (info.scope.is_valid()) - ? info.scope - : ShortcutHelper::GetScopeFromURL(info.url); + return (info.scope.is_valid()) ? info.scope + : ShortcutHelper::GetScopeFromURL(info.url); } // Converts a color from the format specified in content::Manifest to a CSS @@ -95,7 +95,7 @@ #elif defined(__arm__) return "armeabi"; #elif defined(__i386__) - return "x86"; + return "x86"; #elif defined(__mips__) return "mips"; #elif defined(__x86_64__) @@ -126,12 +126,10 @@ webapk::WebAppManifest* web_app_manifest = webapk->mutable_manifest(); web_app_manifest->set_name(base::UTF16ToUTF8(shortcut_info.name)); - web_app_manifest->set_short_name( - base::UTF16ToUTF8(shortcut_info.short_name)); + web_app_manifest->set_short_name(base::UTF16ToUTF8(shortcut_info.short_name)); web_app_manifest->set_start_url(shortcut_info.url.spec()); web_app_manifest->set_orientation( - content::WebScreenOrientationLockTypeToString( - shortcut_info.orientation)); + content::WebScreenOrientationLockTypeToString(shortcut_info.orientation)); web_app_manifest->set_display_mode( content::WebDisplayModeToString(shortcut_info.display)); web_app_manifest->set_background_color( @@ -142,9 +140,10 @@ scope->assign(GetScope(shortcut_info).spec()); webapk::Image* best_image = web_app_manifest->add_icons(); - std::string best_icon_url = shortcut_info.best_icon_url.spec(); - best_image->set_src(best_icon_url); - auto it = icon_url_to_murmur2_hash.find(best_icon_url); + std::string best_primary_icon_url = + shortcut_info.best_primary_icon_url.spec(); + best_image->set_src(best_primary_icon_url); + auto it = icon_url_to_murmur2_hash.find(best_primary_icon_url); if (it != icon_url_to_murmur2_hash.end()) best_image->set_hash(it->second); std::vector<unsigned char> png_bytes; @@ -152,7 +151,7 @@ best_image->set_image_data(&png_bytes.front(), png_bytes.size()); for (const auto& entry : icon_url_to_murmur2_hash) { - if (entry.first == shortcut_info.best_icon_url.spec()) + if (entry.first == shortcut_info.best_primary_icon_url.spec()) continue; webapk::Image* image = web_app_manifest->add_icons(); image->set_src(entry.first); @@ -240,9 +239,9 @@ // The installer will delete itself when it is done. WebApkInstaller* installer = new WebApkInstaller(context, shortcut_info, shortcut_icon); - installer->UpdateAsync( - webapk_package, webapk_version, icon_url_to_murmur2_hash, - is_manifest_stale, finish_callback); + installer->UpdateAsync(webapk_package, webapk_version, + icon_url_to_murmur2_hash, is_manifest_stale, + finish_callback); } // staic @@ -260,9 +259,9 @@ const std::map<std::string, std::string>& icon_url_to_murmur2_hash, bool is_manifest_stale, const FinishCallback& finish_callback) { - installer->UpdateAsync( - webapk_package, webapk_version, icon_url_to_murmur2_hash, - is_manifest_stale, finish_callback); + installer->UpdateAsync(webapk_package, webapk_version, + icon_url_to_murmur2_hash, is_manifest_stale, + finish_callback); } void WebApkInstaller::SetTimeoutMs(int timeout_ms) { @@ -307,14 +306,13 @@ bool WebApkInstaller::StartUpdateUsingDownloadedWebApk( JNIEnv* env, const base::android::ScopedJavaLocalRef<jstring>& java_file_path) { - return Java_WebApkInstaller_updateAsyncFromNative( - env, java_ref_, java_file_path); + return Java_WebApkInstaller_updateAsyncFromNative(env, java_ref_, + java_file_path); } bool WebApkInstaller::CanUseGooglePlayInstallService() { JNIEnv* env = base::android::AttachCurrentThread(); - return Java_WebApkInstaller_canUseGooglePlayInstallService( - env, java_ref_); + return Java_WebApkInstaller_canUseGooglePlayInstallService(env, java_ref_); } bool WebApkInstaller::InstallOrUpdateWebApkFromGooglePlay( @@ -361,8 +359,8 @@ void WebApkInstaller::CreateJavaRef() { JNIEnv* env = base::android::AttachCurrentThread(); - java_ref_.Reset(Java_WebApkInstaller_create( - env, reinterpret_cast<intptr_t>(this))); + java_ref_.Reset( + Java_WebApkInstaller_create(env, reinterpret_cast<intptr_t>(this))); } void WebApkInstaller::InstallAsync(const FinishCallback& finish_callback) { @@ -396,7 +394,7 @@ base::Bind(&BuildWebApkProtoInBackground, shortcut_info_, shortcut_icon_, icon_url_to_murmur2_hash, is_manifest_stale), base::Bind(&WebApkInstaller::SendUpdateWebApkRequest, - weak_ptr_factory_.GetWeakPtr())); + weak_ptr_factory_.GetWeakPtr())); } void WebApkInstaller::OnURLFetchComplete(const net::URLFetcher* source) { @@ -411,8 +409,7 @@ std::string response_string; source->GetResponseAsString(&response_string); - std::unique_ptr<webapk::WebApkResponse> response( - new webapk::WebApkResponse); + std::unique_ptr<webapk::WebApkResponse> response(new webapk::WebApkResponse); if (!response->ParseFromString(response_string)) { OnFailure(); return; @@ -427,10 +424,12 @@ if (CanUseGooglePlayInstallService()) { int version = 1; base::StringToInt(response->version(), &version); - if (!InstallOrUpdateWebApkFromGooglePlay( - response->package_name(), version, response->token())) { - OnFailure(); - } + // TODO(hanxi): crbug.com/688759. Remove the return value of + // InstallOrUpdateWebApkFromGooglePlay(), since a callback will be called + // asynchronously after the install or upidate has either failed or + // completed. + InstallOrUpdateWebApkFromGooglePlay(response->package_name(), version, + response->token()); return; } @@ -439,7 +438,7 @@ void WebApkInstaller::DownloadAppIconAndComputeMurmur2Hash() { // Safeguard. WebApkIconHasher crashes if asked to fetch an invalid URL. - if (!shortcut_info_.best_icon_url.is_valid()) { + if (!shortcut_info_.best_primary_icon_url.is_valid()) { OnFailure(); return; } @@ -450,7 +449,7 @@ icon_hasher_.reset(new WebApkIconHasher()); icon_hasher_->DownloadAndComputeMurmur2Hash( - request_context_getter_, shortcut_info_.best_icon_url, + request_context_getter_, shortcut_info_.best_primary_icon_url, base::Bind(&WebApkInstaller::OnGotIconMurmur2Hash, weak_ptr_factory_.GetWeakPtr())); } @@ -468,7 +467,7 @@ std::map<std::string, std::string> icon_url_to_murmur2_hash; for (const std::string& icon_url : shortcut_info_.icon_urls) { - if (icon_url != shortcut_info_.best_icon_url.spec()) + if (icon_url != shortcut_info_.best_primary_icon_url.spec()) icon_url_to_murmur2_hash[icon_url] = ""; else icon_url_to_murmur2_hash[icon_url] = icon_murmur2_hash; @@ -508,10 +507,9 @@ std::string serialized_request; request_proto->SerializeToString(&serialized_request); url_fetcher_->SetUploadData(kProtoMimeType, serialized_request); - url_fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE | - net::LOAD_DO_NOT_SEND_COOKIES | - net::LOAD_DO_NOT_SAVE_COOKIES | - net::LOAD_DO_NOT_SEND_AUTH_DATA); + url_fetcher_->SetLoadFlags( + net::LOAD_DISABLE_CACHE | net::LOAD_DO_NOT_SEND_COOKIES | + net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_AUTH_DATA); url_fetcher_->Start(); } @@ -529,14 +527,15 @@ } void WebApkInstaller::OnCreatedSubDirAndSetPermissions( - const GURL& download_url, const base::FilePath& output_dir) { + const GURL& download_url, + const base::FilePath& output_dir) { if (output_dir.empty()) { OnFailure(); return; } - DownloadWebApk(output_dir.AppendASCII(webapk_package_ + ".apk"), - download_url, true); + DownloadWebApk(output_dir.AppendASCII(webapk_package_ + ".apk"), download_url, + true); } void WebApkInstaller::DownloadWebApk(const base::FilePath& output_path, @@ -549,8 +548,8 @@ downloader_.reset(new FileDownloader( download_url, output_path, true, request_context_getter_, base::Bind(&WebApkInstaller::OnWebApkDownloaded, - weak_ptr_factory_.GetWeakPtr(), - output_path, download_url, retry_if_fails))); + weak_ptr_factory_.GetWeakPtr(), output_path, download_url, + retry_if_fails))); } void WebApkInstaller::OnWebApkDownloaded(const base::FilePath& file_path, @@ -568,8 +567,8 @@ content::BrowserThread::PostDelayedTask( content::BrowserThread::UI, FROM_HERE, base::Bind(&WebApkInstaller::DownloadWebApk, - weak_ptr_factory_.GetWeakPtr(), - file_path, download_url, false), + weak_ptr_factory_.GetWeakPtr(), file_path, download_url, + false), base::TimeDelta::FromSeconds(2)); return; } @@ -599,8 +598,8 @@ base::android::ConvertUTF8ToJavaString(env, webapk_package_); bool success = false; if (task_type_ == INSTALL) { - success = StartInstallingDownloadedWebApk(env, java_file_path, - java_package_name); + success = + StartInstallingDownloadedWebApk(env, java_file_path, java_package_name); } else if (task_type_ == UPDATE) { success = StartUpdateUsingDownloadedWebApk(env, java_file_path); if (success) {
diff --git a/chrome/browser/android/webapk/webapk_installer.h b/chrome/browser/android/webapk/webapk_installer.h index 94b807c..bfb925f0 100644 --- a/chrome/browser/android/webapk/webapk_installer.h +++ b/chrome/browser/android/webapk/webapk_installer.h
@@ -52,9 +52,9 @@ // install the downloaded WebAPK. Calls |callback| once the install completed // or failed. static void InstallAsync(content::BrowserContext* context, - const ShortcutInfo& shortcut_info, - const SkBitmap& shortcut_icon, - const FinishCallback& finish_callback); + const ShortcutInfo& shortcut_info, + const SkBitmap& shortcut_icon, + const FinishCallback& finish_callback); // Creates a self-owned WebApkInstaller instance and talks to the Chrome // WebAPK server to update a WebAPK on the server and to the Google Play
diff --git a/chrome/browser/android/webapk/webapk_installer_unittest.cc b/chrome/browser/android/webapk/webapk_installer_unittest.cc index 1fddb62..0728546e 100644 --- a/chrome/browser/android/webapk/webapk_installer_unittest.cc +++ b/chrome/browser/android/webapk/webapk_installer_unittest.cc
@@ -39,10 +39,10 @@ // URL of mock WebAPK server. const char* kServerUrl = "/webapkserver/"; -// The best icon URL from Web Manifest. We use a random file in the test data -// directory. Since WebApkInstaller does not try to decode the file as an image -// it is OK that the file is not an image. -const char* kBestIconUrl = "/simple.html"; +// The best primary icon URL from Web Manifest. We use a random file in the test +// data directory. Since WebApkInstaller does not try to decode the file as an +// image it is OK that the file is not an image. +const char* kBestPrimaryIconUrl = "/simple.html"; // URL of file to download from the WebAPK server. We use a random file in the // test data directory. @@ -109,9 +109,9 @@ class WebApkInstallerRunner { public: WebApkInstallerRunner(content::BrowserContext* browser_context, - const GURL& best_icon_url) + const GURL& best_primary_icon_url) : browser_context_(browser_context), - best_icon_url_(best_icon_url), + best_primary_icon_url_(best_primary_icon_url), can_use_google_play_install_service_(false) {} ~WebApkInstallerRunner() {} @@ -123,24 +123,20 @@ void RunInstallWebApk() { WebApkInstaller::InstallAsyncForTesting( - CreateWebApkInstaller(), - base::Bind(&WebApkInstallerRunner::OnCompleted, - base::Unretained(this))); + CreateWebApkInstaller(), base::Bind(&WebApkInstallerRunner::OnCompleted, + base::Unretained(this))); Run(); } void RunUpdateWebApk() { const int kWebApkVersion = 1; - std::map<std::string, std::string> icon_url_to_murmur2_hash { - {best_icon_url_.spec(), "0"} }; + std::map<std::string, std::string> icon_url_to_murmur2_hash{ + {best_primary_icon_url_.spec(), "0"}}; WebApkInstaller::UpdateAsyncForTesting( - CreateWebApkInstaller(), - kDownloadedWebApkPackageName, - kWebApkVersion, - icon_url_to_murmur2_hash, - false /* is_manifest_stale */, + CreateWebApkInstaller(), kDownloadedWebApkPackageName, kWebApkVersion, + icon_url_to_murmur2_hash, false /* is_manifest_stale */, base::Bind(&WebApkInstallerRunner::OnCompleted, base::Unretained(this))); Run(); @@ -148,7 +144,7 @@ WebApkInstaller* CreateWebApkInstaller() { ShortcutInfo info(GURL::EmptyGURL()); - info.best_icon_url = best_icon_url_; + info.best_primary_icon_url = best_primary_icon_url_; // WebApkInstaller owns itself. WebApkInstaller* installer = @@ -175,7 +171,7 @@ content::BrowserContext* browser_context_; // The Web Manifest's icon URL. - const GURL best_icon_url_; + const GURL best_primary_icon_url_; // Called after the installation process has succeeded or failed. base::Closure on_completed_callback_; @@ -217,11 +213,11 @@ ~BuildProtoRunner() {} void BuildSync( - const GURL& best_icon_url, + const GURL& best_primary_icon_url, const std::map<std::string, std::string>& icon_url_to_murmur2_hash, bool is_manifest_stale) { ShortcutInfo info(GURL::EmptyGURL()); - info.best_icon_url = best_icon_url; + info.best_primary_icon_url = best_primary_icon_url; // WebApkInstaller owns itself. WebApkInstaller* installer = @@ -229,8 +225,7 @@ installer->BuildWebApkProtoInBackgroundForTesting( base::Bind(&BuildProtoRunner::OnBuiltWebApkProto, base::Unretained(this)), - icon_url_to_murmur2_hash, - is_manifest_stale); + icon_url_to_murmur2_hash, is_manifest_stale); base::RunLoop run_loop; on_completed_callback_ = run_loop.QuitClosure(); @@ -270,9 +265,8 @@ void SetUp() override { test_server_.AddDefaultHandlers(base::FilePath(kTestDataDir)); - test_server_.RegisterRequestHandler( - base::Bind(&WebApkInstallerTest::HandleWebApkRequest, - base::Unretained(this))); + test_server_.RegisterRequestHandler(base::Bind( + &WebApkInstallerTest::HandleWebApkRequest, base::Unretained(this))); ASSERT_TRUE(test_server_.Start()); profile_.reset(new TestingProfile()); @@ -285,9 +279,9 @@ base::RunLoop().RunUntilIdle(); } - // Sets the best Web Manifest's icon URL. - void SetBestIconUrl(const GURL& best_icon_url) { - best_icon_url_ = best_icon_url; + // Sets the best Web Manifest's primary icon URL. + void SetBestPrimaryIconUrl(const GURL& best_primary_icon_url) { + best_primary_icon_url_ = best_primary_icon_url; } // Sets the URL to send the webapk::CreateWebApkRequest to. WebApkInstaller @@ -305,7 +299,7 @@ std::unique_ptr<WebApkInstallerRunner> CreateWebApkInstallerRunner() { return std::unique_ptr<WebApkInstallerRunner>( - new WebApkInstallerRunner(profile_.get(), best_icon_url_)); + new WebApkInstallerRunner(profile_.get(), best_primary_icon_url_)); } std::unique_ptr<BuildProtoRunner> CreateBuildProtoRunner() { @@ -318,8 +312,8 @@ private: // Sets default configuration for running WebApkInstaller. void SetDefaults() { - GURL best_icon_url = test_server_.GetURL(kBestIconUrl); - SetBestIconUrl(best_icon_url); + GURL best_primary_icon_url = test_server_.GetURL(kBestPrimaryIconUrl); + SetBestPrimaryIconUrl(best_primary_icon_url); GURL server_url = test_server_.GetURL(kServerUrl); SetWebApkServerUrl(server_url); GURL download_url = test_server_.GetURL(kDownloadUrl); @@ -339,7 +333,7 @@ net::EmbeddedTestServer test_server_; // Web Manifest's icon URL. - GURL best_icon_url_; + GURL best_primary_icon_url_; // Builds response to the WebAPK creation request. WebApkResponseBuilder webapk_response_builder_; @@ -354,12 +348,12 @@ EXPECT_TRUE(runner->success()); } -// Test that installation fails if fetching the bitmap at the best icon URL -// times out. In a perfect world the fetch would never time out because the -// bitmap at the best icon URL should be in the HTTP cache. -TEST_F(WebApkInstallerTest, BestIconUrlDownloadTimesOut) { - GURL best_icon_url = test_server()->GetURL("/slow?1000"); - SetBestIconUrl(best_icon_url); +// Test that installation fails if fetching the bitmap at the best primary icon +// URL times out. In a perfect world the fetch would never time out because the +// bitmap at the best primary icon URL should be in the HTTP cache. +TEST_F(WebApkInstallerTest, BestPrimaryIconUrlDownloadTimesOut) { + GURL best_primary_icon_url = test_server()->GetURL("/slow?1000"); + SetBestPrimaryIconUrl(best_primary_icon_url); std::unique_ptr<WebApkInstallerRunner> runner = CreateWebApkInstallerRunner(); runner->RunInstallWebApk(); @@ -435,9 +429,9 @@ EXPECT_TRUE(runner->success()); } -// When there is no Web Manifest available for a site, an empty |best_icon_url| -// is used to build a WebApk update request. Tests the request can be built -// properly. +// When there is no Web Manifest available for a site, an empty +// |best_primary_icon_url| is used to build a WebApk update request. Tests the +// request can be built properly. TEST_F(WebApkInstallerTest, BuildWebApkProtoWhenManifestIsObsolete) { GURL icon_url_1 = test_server()->GetURL("/icon1.png"); GURL icon_url_2 = test_server()->GetURL("/icon2.png"); @@ -477,16 +471,16 @@ // knows the best icon URL of a site after fetching its Web Manifest. TEST_F(WebApkInstallerTest, BuildWebApkProtoWhenManifestIsAvailable) { GURL icon_url_1 = test_server()->GetURL("/icon.png"); - GURL best_icon_url = test_server()->GetURL(kBestIconUrl); + GURL best_primary_icon_url = test_server()->GetURL(kBestPrimaryIconUrl); std::string icon_murmur2_hash_1 = "1"; - std::string best_icon_murmur2_hash = "0"; + std::string best_primary_icon_murmur2_hash = "0"; std::map<std::string, std::string> icon_url_to_murmur2_hash; icon_url_to_murmur2_hash[icon_url_1.spec()] = icon_murmur2_hash_1; - icon_url_to_murmur2_hash[best_icon_url.spec()] = - best_icon_murmur2_hash; + icon_url_to_murmur2_hash[best_primary_icon_url.spec()] = + best_primary_icon_murmur2_hash; std::unique_ptr<BuildProtoRunner> runner = CreateBuildProtoRunner(); - runner->BuildSync(best_icon_url, icon_url_to_murmur2_hash, + runner->BuildSync(best_primary_icon_url, icon_url_to_murmur2_hash, false /* is_manifest_stale*/); webapk::WebApk* webapk_request = runner->GetWebApkRequest(); ASSERT_NE(nullptr, webapk_request); @@ -498,8 +492,8 @@ for (int i = 0; i < 2; ++i) icons[i] = manifest.icons(i); - EXPECT_EQ(best_icon_url.spec(), icons[0].src()); - EXPECT_EQ(best_icon_murmur2_hash, icons[0].hash()); + EXPECT_EQ(best_primary_icon_url.spec(), icons[0].src()); + EXPECT_EQ(best_primary_icon_murmur2_hash, icons[0].hash()); EXPECT_TRUE(icons[0].has_image_data()); EXPECT_EQ(icon_url_1.spec(), icons[1].src());
diff --git a/chrome/browser/android/webapk/webapk_update_data_fetcher.cc b/chrome/browser/android/webapk/webapk_update_data_fetcher.cc index 72d1c16..5b8e87a 100644 --- a/chrome/browser/android/webapk/webapk_update_data_fetcher.cc +++ b/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
@@ -30,7 +30,7 @@ // Returns whether the given |url| is within the scope of the |scope| url. bool IsInScope(const GURL& url, const GURL& scope) { return base::StartsWith(url.spec(), scope.spec(), - base::CompareCase::SENSITIVE); + base::CompareCase::SENSITIVE); } } // anonymous namespace @@ -40,18 +40,17 @@ const JavaParamRef<jstring>& java_scope_url, const JavaParamRef<jstring>& java_web_manifest_url) { GURL scope(base::android::ConvertJavaStringToUTF8(env, java_scope_url)); - GURL web_manifest_url(base::android::ConvertJavaStringToUTF8( - env, java_web_manifest_url)); + GURL web_manifest_url( + base::android::ConvertJavaStringToUTF8(env, java_web_manifest_url)); WebApkUpdateDataFetcher* fetcher = new WebApkUpdateDataFetcher(env, obj, scope, web_manifest_url); return reinterpret_cast<intptr_t>(fetcher); } -WebApkUpdateDataFetcher::WebApkUpdateDataFetcher( - JNIEnv* env, - jobject obj, - const GURL& scope, - const GURL& web_manifest_url) +WebApkUpdateDataFetcher::WebApkUpdateDataFetcher(JNIEnv* env, + jobject obj, + const GURL& scope, + const GURL& web_manifest_url) : content::WebContentsObserver(nullptr), scope_(scope), web_manifest_url_(web_manifest_url), @@ -61,8 +60,7 @@ java_ref_.Reset(env, obj); } -WebApkUpdateDataFetcher::~WebApkUpdateDataFetcher() { -} +WebApkUpdateDataFetcher::~WebApkUpdateDataFetcher() {} // static bool WebApkUpdateDataFetcher::Register(JNIEnv* env) { @@ -122,9 +120,8 @@ InstallableManager* installable_manager = InstallableManager::FromWebContents(web_contents()); installable_manager->GetData( - params, - base::Bind(&WebApkUpdateDataFetcher::OnDidGetInstallableData, - weak_ptr_factory_.GetWeakPtr())); + params, base::Bind(&WebApkUpdateDataFetcher::OnDidGetInstallableData, + weak_ptr_factory_.GetWeakPtr())); } void WebApkUpdateDataFetcher::OnDidGetInstallableData( @@ -143,8 +140,8 @@ // observing too. It is based on our assumption that it is invalid for // web developers to change the Web Manifest location. When it does // change, we will treat the new Web Manifest as the one of another WebAPK. - if (data.error_code != NO_ERROR_DETECTED || - data.manifest.IsEmpty() || web_manifest_url_ != data.manifest_url || + if (data.error_code != NO_ERROR_DETECTED || data.manifest.IsEmpty() || + web_manifest_url_ != data.manifest_url || !AreWebManifestUrlsWebApkCompatible(data.manifest)) { OnWebManifestNotWebApkCompatible(); return; @@ -152,35 +149,34 @@ info_.UpdateFromManifest(data.manifest); info_.manifest_url = data.manifest_url; - info_.best_icon_url = data.primary_icon_url; - best_icon_ = *data.primary_icon; + info_.best_primary_icon_url = data.primary_icon_url; + best_primary_icon_ = *data.primary_icon; icon_hasher_.reset(new WebApkIconHasher()); Profile* profile = Profile::FromBrowserContext(web_contents()->GetBrowserContext()); icon_hasher_->DownloadAndComputeMurmur2Hash( - profile->GetRequestContext(), - data.primary_icon_url, + profile->GetRequestContext(), data.primary_icon_url, base::Bind(&WebApkUpdateDataFetcher::OnGotIconMurmur2Hash, weak_ptr_factory_.GetWeakPtr())); } void WebApkUpdateDataFetcher::OnGotIconMurmur2Hash( - const std::string& best_icon_murmur2_hash) { + const std::string& best_primary_icon_murmur2_hash) { icon_hasher_.reset(); - if (best_icon_murmur2_hash.empty()) { + if (best_primary_icon_murmur2_hash.empty()) { OnWebManifestNotWebApkCompatible(); return; } - OnDataAvailable(info_, best_icon_murmur2_hash, best_icon_); + OnDataAvailable(info_, best_primary_icon_murmur2_hash, best_primary_icon_); } void WebApkUpdateDataFetcher::OnDataAvailable( const ShortcutInfo& info, - const std::string& best_icon_murmur2_hash, - const SkBitmap& best_icon_bitmap) { + const std::string& best_primary_icon_murmur2_hash, + const SkBitmap& best_primary_icon) { JNIEnv* env = base::android::AttachCurrentThread(); ScopedJavaLocalRef<jstring> java_url = @@ -191,21 +187,23 @@ base::android::ConvertUTF16ToJavaString(env, info.name); ScopedJavaLocalRef<jstring> java_short_name = base::android::ConvertUTF16ToJavaString(env, info.short_name); - ScopedJavaLocalRef<jstring> java_best_icon_url = - base::android::ConvertUTF8ToJavaString(env, info.best_icon_url.spec()); - ScopedJavaLocalRef<jstring> java_best_icon_murmur2_hash = - base::android::ConvertUTF8ToJavaString(env, best_icon_murmur2_hash); - ScopedJavaLocalRef<jobject> java_best_bitmap = - gfx::ConvertToJavaBitmap(&best_icon_bitmap); + ScopedJavaLocalRef<jstring> java_best_primary_icon_url = + base::android::ConvertUTF8ToJavaString(env, + info.best_primary_icon_url.spec()); + ScopedJavaLocalRef<jstring> java_best_primary_icon_murmur2_hash = + base::android::ConvertUTF8ToJavaString(env, + best_primary_icon_murmur2_hash); + ScopedJavaLocalRef<jobject> java_best_primary_icon = + gfx::ConvertToJavaBitmap(&best_primary_icon); ScopedJavaLocalRef<jobjectArray> java_icon_urls = base::android::ToJavaArrayOfStrings(env, info.icon_urls); Java_WebApkUpdateDataFetcher_onDataAvailable( env, java_ref_, java_url, java_scope, java_name, java_short_name, - java_best_icon_url, java_best_icon_murmur2_hash, java_best_bitmap, - java_icon_urls, info.display, info.orientation, info.theme_color, - info.background_color); + java_best_primary_icon_url, java_best_primary_icon_murmur2_hash, + java_best_primary_icon, java_icon_urls, info.display, info.orientation, + info.theme_color, info.background_color); } void WebApkUpdateDataFetcher::OnWebManifestNotWebApkCompatible() {
diff --git a/chrome/browser/android/webapk/webapk_update_data_fetcher.h b/chrome/browser/android/webapk/webapk_update_data_fetcher.h index 03f3dac..8e6ebf8 100644 --- a/chrome/browser/android/webapk/webapk_update_data_fetcher.h +++ b/chrome/browser/android/webapk/webapk_update_data_fetcher.h
@@ -62,11 +62,11 @@ void OnDidGetInstallableData(const InstallableData& installable_data); // Called with the computed Murmur2 hash for the app icon. - void OnGotIconMurmur2Hash(const std::string& best_icon_murmur2_hash); + void OnGotIconMurmur2Hash(const std::string& best_primary_icon_murmur2_hash); void OnDataAvailable(const ShortcutInfo& info, - const std::string& best_icon_murmur2_hash, - const SkBitmap& best_icon); + const std::string& best_primary_icon_murmur2_hash, + const SkBitmap& best_primary_icon); // Called when a page has no Web Manifest or the Web Manifest is not WebAPK // compatible. @@ -92,7 +92,7 @@ // Downloaded data for |web_manifest_url_|. ShortcutInfo info_; - SkBitmap best_icon_; + SkBitmap best_primary_icon_; base::WeakPtrFactory<WebApkUpdateDataFetcher> weak_ptr_factory_;
diff --git a/chrome/browser/android/webapk/webapk_update_manager.cc b/chrome/browser/android/webapk/webapk_update_manager.cc index 835cb60..235dab3 100644 --- a/chrome/browser/android/webapk/webapk_update_manager.cc +++ b/chrome/browser/android/webapk/webapk_update_manager.cc
@@ -54,8 +54,8 @@ const JavaParamRef<jstring>& java_scope, const JavaParamRef<jstring>& java_name, const JavaParamRef<jstring>& java_short_name, - const JavaParamRef<jstring>& java_best_icon_url, - const JavaParamRef<jobject>& java_best_icon_bitmap, + const JavaParamRef<jstring>& java_best_primary_icon_url, + const JavaParamRef<jobject>& java_best_primary_icon_bitmap, const JavaParamRef<jobjectArray>& java_icon_urls, const JavaParamRef<jobjectArray>& java_icon_hashes, jint java_display_mode, @@ -78,7 +78,8 @@ GURL start_url(ConvertJavaStringToUTF8(env, java_start_url)); GURL scope(ConvertJavaStringToUTF8(env, java_scope)); GURL web_manifest_url(ConvertJavaStringToUTF8(env, java_web_manifest_url)); - GURL best_icon_url(ConvertJavaStringToUTF8(env, java_best_icon_url)); + GURL best_primary_icon_url( + ConvertJavaStringToUTF8(env, java_best_primary_icon_url)); ShortcutInfo info(start_url); info.scope = scope; info.name = ConvertJavaStringToUTF16(env, java_name); @@ -89,11 +90,11 @@ static_cast<blink::WebScreenOrientationLockType>(java_orientation); info.theme_color = (long)java_theme_color; info.background_color = (long)java_background_color; - info.best_icon_url = best_icon_url; + info.best_primary_icon_url = best_primary_icon_url; info.manifest_url = web_manifest_url; - base::android::AppendJavaStringArrayToStringVector( - env, java_icon_urls.obj(), &info.icon_urls); + base::android::AppendJavaStringArrayToStringVector(env, java_icon_urls.obj(), + &info.icon_urls); std::vector<std::string> icon_hashes; base::android::AppendJavaStringArrayToStringVector( @@ -103,10 +104,10 @@ for (size_t i = 0; i < info.icon_urls.size(); ++i) icon_url_to_murmur2_hash[info.icon_urls[i]] = icon_hashes[i]; - gfx::JavaBitmap java_bitmap_lock(java_best_icon_bitmap); - SkBitmap best_icon_bitmap = + gfx::JavaBitmap java_bitmap_lock(java_best_primary_icon_bitmap); + SkBitmap best_primary_icon_bitmap = gfx::CreateSkBitmapFromJavaBitmap(java_bitmap_lock); - best_icon_bitmap.setImmutable(); + best_primary_icon_bitmap.setImmutable(); std::string webapk_package; ConvertJavaStringToUTF8(env, java_webapk_package, &webapk_package); @@ -119,7 +120,7 @@ return; } install_service->UpdateAsync( - info, best_icon_bitmap, webapk_package, java_webapk_version, + info, best_primary_icon_bitmap, webapk_package, java_webapk_version, icon_url_to_murmur2_hash, java_is_manifest_stale, base::Bind(&WebApkUpdateManager::OnBuiltWebApk, id)); }
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc index 4ad906bb..9f7d15a 100644 --- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc +++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
@@ -240,7 +240,7 @@ weak_observer_->OnUserTitleAvailable(shortcut_info_.user_title); if (data.primary_icon) { - shortcut_info_.best_icon_url = data.primary_icon_url; + shortcut_info_.best_primary_icon_url = data.primary_icon_url; CreateLauncherIcon(*(data.primary_icon)); return; @@ -296,19 +296,17 @@ bitmap_result.bitmap_data->size(), &raw_icon); } - shortcut_info_.best_icon_url = bitmap_result.icon_url; + shortcut_info_.best_primary_icon_url = bitmap_result.icon_url; CreateLauncherIconInBackground(raw_icon); } void AddToHomescreenDataFetcher::CreateLauncherIcon(const SkBitmap& raw_icon) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - content::BrowserThread::GetBlockingPool() - ->PostWorkerTaskWithShutdownBehavior( - FROM_HERE, - base::Bind( - &AddToHomescreenDataFetcher::CreateLauncherIconInBackground, - this, raw_icon), - base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + content::BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior( + FROM_HERE, + base::Bind(&AddToHomescreenDataFetcher::CreateLauncherIconInBackground, + this, raw_icon), + base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); } void AddToHomescreenDataFetcher::CreateLauncherIconInBackground( @@ -323,7 +321,7 @@ } if (is_generated) - shortcut_info_.best_icon_url = GURL(); + shortcut_info_.best_primary_icon_url = GURL(); content::BrowserThread::PostTask( content::BrowserThread::UI, FROM_HERE,
diff --git a/chrome/browser/android/webapps/add_to_homescreen_manager.cc b/chrome/browser/android/webapps/add_to_homescreen_manager.cc index 3608e943e..9d4dc4f 100644 --- a/chrome/browser/android/webapps/add_to_homescreen_manager.cc +++ b/chrome/browser/android/webapps/add_to_homescreen_manager.cc
@@ -76,7 +76,7 @@ void AddToHomescreenManager::Start(content::WebContents* web_contents) { bool check_webapk_compatible = false; - if (ChromeWebApkHost::AreWebApkEnabled() && + if (ChromeWebApkHost::CanInstallWebApk() && InstallableManager::IsContentSecure(web_contents)) { check_webapk_compatible = true; } else {
diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc index d61b3e7..16b1fa07 100644 --- a/chrome/browser/browser_about_handler.cc +++ b/chrome/browser/browser_about_handler.cc
@@ -20,6 +20,7 @@ #include "chrome/common/chrome_switches.h" #include "chrome/common/url_constants.h" #include "components/url_formatter/url_fixer.h" +#include "content/public/common/content_features.h" #include "extensions/features/features.h" #if !defined(OS_ANDROID) @@ -88,8 +89,7 @@ #if defined(OS_ANDROID) // TODO(twellington): remove this after native Android history launches. // See http://crbug.com/654071. - if (!base::FeatureList::IsEnabled( - chrome::android::kNativeAndroidHistoryManager)) { + if (!base::FeatureList::IsEnabled(features::kNativeAndroidHistoryManager)) { // On Android, redirect directly to chrome://history-frame since // uber page is unsupported. host = chrome::kChromeUIHistoryFrameHost;
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index 576408b..c6d40d4 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd
@@ -640,6 +640,9 @@ <include name="IDR_WELCOME_WIN10_PIN_LARGE_WEBP" file="resources\welcome\win10\pin-large.webp" type="BINDATA" /> <include name="IDR_WELCOME_WIN10_PIN_SMALL_WEBP" file="resources\welcome\win10\pin-small.webp" type="BINDATA" /> </if> + <if expr="not is_android and not is_ios"> + <include name="IDR_SSL_ERROR_ASSISTANT_PB" file="${root_gen_dir}/chrome/browser/resources/ssl/ssl_error_assistant/ssl_error_assistant.pb" use_base_dir="false" type="BINDATA" /> + </if> </includes> </release> </grit>
diff --git a/chrome/browser/browsing_data/browsing_data_helper.cc b/chrome/browser/browsing_data/browsing_data_helper.cc index a40de7a..6e4fcbe 100644 --- a/chrome/browser/browsing_data/browsing_data_helper.cc +++ b/chrome/browser/browsing_data/browsing_data_helper.cc
@@ -4,22 +4,18 @@ #include "chrome/browser/browsing_data/browsing_data_helper.h" +#include <vector> + #include "base/strings/utf_string_conversions.h" -#include "chrome/common/url_constants.h" -#include "content/public/browser/child_process_security_policy.h" #include "extensions/common/constants.h" #include "storage/browser/quota/special_storage_policy.h" #include "url/gurl.h" +#include "url/url_util.h" // Static bool BrowsingDataHelper::IsWebScheme(const std::string& scheme) { - // All "web safe" schemes are valid, except `chrome-extension://` - // and `chrome-devtools://`. - content::ChildProcessSecurityPolicy* policy = - content::ChildProcessSecurityPolicy::GetInstance(); - return (policy->IsWebSafeScheme(scheme) && - !BrowsingDataHelper::IsExtensionScheme(scheme) && - scheme != content::kChromeDevToolsScheme); + const std::vector<std::string>& schemes = url::GetWebStorageSchemes(); + return std::find(schemes.begin(), schemes.end(), scheme) != schemes.end(); } // Static
diff --git a/chrome/browser/browsing_data/browsing_data_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_helper_unittest.cc index f5ff40f..5bf6ac4 100644 --- a/chrome/browser/browsing_data/browsing_data_helper_unittest.cc +++ b/chrome/browser/browsing_data/browsing_data_helper_unittest.cc
@@ -61,18 +61,16 @@ DISALLOW_COPY_AND_ASSIGN(BrowsingDataHelperTest); }; -TEST_F(BrowsingDataHelperTest, WebSafeSchemesAreWebSafe) { +TEST_F(BrowsingDataHelperTest, WebStorageSchemesAreWebSchemes) { EXPECT_TRUE(IsWebScheme(url::kHttpScheme)); EXPECT_TRUE(IsWebScheme(url::kHttpsScheme)); + EXPECT_TRUE(IsWebScheme(url::kFileScheme)); EXPECT_TRUE(IsWebScheme(url::kFtpScheme)); - EXPECT_TRUE(IsWebScheme(url::kDataScheme)); - EXPECT_TRUE(IsWebScheme("feed")); - EXPECT_TRUE(IsWebScheme(url::kBlobScheme)); - EXPECT_TRUE(IsWebScheme(url::kFileSystemScheme)); - EXPECT_FALSE(IsWebScheme("invalid-scheme-i-just-made-up")); + EXPECT_TRUE(IsWebScheme(url::kWsScheme)); + EXPECT_TRUE(IsWebScheme(url::kWssScheme)); } -TEST_F(BrowsingDataHelperTest, ChromeSchemesAreNotWebSafe) { +TEST_F(BrowsingDataHelperTest, ChromeSchemesAreNotWebSchemes) { EXPECT_FALSE(IsWebScheme(extensions::kExtensionScheme)); EXPECT_FALSE(IsWebScheme(url::kAboutScheme)); EXPECT_FALSE(IsWebScheme(content::kChromeDevToolsScheme)); @@ -82,15 +80,13 @@ EXPECT_FALSE(IsWebScheme(content::kViewSourceScheme)); } -TEST_F(BrowsingDataHelperTest, WebSafeSchemesAreNotExtensions) { +TEST_F(BrowsingDataHelperTest, WebStorageSchemesAreNotExtensions) { EXPECT_FALSE(IsExtensionScheme(url::kHttpScheme)); EXPECT_FALSE(IsExtensionScheme(url::kHttpsScheme)); + EXPECT_FALSE(IsExtensionScheme(url::kFileScheme)); EXPECT_FALSE(IsExtensionScheme(url::kFtpScheme)); - EXPECT_FALSE(IsExtensionScheme(url::kDataScheme)); - EXPECT_FALSE(IsExtensionScheme("feed")); - EXPECT_FALSE(IsExtensionScheme(url::kBlobScheme)); - EXPECT_FALSE(IsExtensionScheme(url::kFileSystemScheme)); - EXPECT_FALSE(IsExtensionScheme("invalid-scheme-i-just-made-up")); + EXPECT_FALSE(IsExtensionScheme(url::kWsScheme)); + EXPECT_FALSE(IsExtensionScheme(url::kWssScheme)); } TEST_F(BrowsingDataHelperTest, ChromeSchemesAreNotAllExtension) { @@ -104,6 +100,23 @@ EXPECT_FALSE(IsExtensionScheme(content::kViewSourceScheme)); } +TEST_F(BrowsingDataHelperTest, SchemesThatCantStoreDataDontMatchAnything) { + EXPECT_FALSE(IsWebScheme(url::kDataScheme)); + EXPECT_FALSE(IsExtensionScheme(url::kDataScheme)); + + EXPECT_FALSE(IsWebScheme("feed")); + EXPECT_FALSE(IsExtensionScheme("feed")); + + EXPECT_FALSE(IsWebScheme(url::kBlobScheme)); + EXPECT_FALSE(IsExtensionScheme(url::kBlobScheme)); + + EXPECT_FALSE(IsWebScheme(url::kFileSystemScheme)); + EXPECT_FALSE(IsExtensionScheme(url::kFileSystemScheme)); + + EXPECT_FALSE(IsWebScheme("invalid-scheme-i-just-made-up")); + EXPECT_FALSE(IsExtensionScheme("invalid-scheme-i-just-made-up")); +} + #if BUILDFLAG(ENABLE_EXTENSIONS) TEST_F(BrowsingDataHelperTest, TestMatches) { scoped_refptr<MockExtensionSpecialStoragePolicy> mock_policy =
diff --git a/chrome/browser/budget_service/OWNERS b/chrome/browser/budget_service/OWNERS index 6391f8c7..0be0ee4 100644 --- a/chrome/browser/budget_service/OWNERS +++ b/chrome/browser/budget_service/OWNERS
@@ -1,3 +1,5 @@ harkness@chromium.org johnme@chromium.org peter@chromium.org + +# COMPONENT: Blink>PushAPI
diff --git a/chrome/browser/chrome_browser_main_linux.cc b/chrome/browser/chrome_browser_main_linux.cc index bbc21dda..3252c0e 100644 --- a/chrome/browser/chrome_browser_main_linux.cc +++ b/chrome/browser/chrome_browser_main_linux.cc
@@ -8,6 +8,7 @@ #include <string> +#include "base/task_scheduler/post_task.h" #include "build/build_config.h" #include "chrome/browser/browser_process.h" #include "chrome/grit/chromium_strings.h" @@ -48,8 +49,9 @@ // Needs to be called after we have chrome::DIR_USER_DATA and // g_browser_process. This happens in PreCreateThreads. // base::GetLinuxDistro() will initialize its value if needed. - content::BrowserThread::PostBlockingPoolTask( - FROM_HERE, + base::PostTaskWithTraits( + FROM_HERE, base::TaskTraits().MayBlock().WithPriority( + base::TaskPriority::BACKGROUND), base::Bind(base::IgnoreResult(&base::GetLinuxDistro))); #endif
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index fdd79c2..c206c0ff 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -227,7 +227,9 @@ "arc/arc_support_host.h", "arc/arc_util.cc", "arc/arc_util.h", - "arc/auth/arc_auth_code_fetcher.h", + "arc/auth/arc_active_directory_enrollment_token_fetcher.cc", + "arc/auth/arc_active_directory_enrollment_token_fetcher.h", + "arc/auth/arc_auth_info_fetcher.h", "arc/auth/arc_background_auth_code_fetcher.cc", "arc/auth/arc_background_auth_code_fetcher.h", "arc/auth/arc_manual_auth_code_fetcher.cc", @@ -820,8 +822,6 @@ "login/screens/terms_of_service_screen.cc", "login/screens/terms_of_service_screen.h", "login/screens/terms_of_service_screen_actor.h", - "login/screens/update_model.cc", - "login/screens/update_model.h", "login/screens/update_screen.cc", "login/screens/update_screen.h", "login/screens/update_view.h", @@ -908,8 +908,6 @@ "login/ui/login_feedback.h", "login/ui/login_web_dialog.cc", "login/ui/login_web_dialog.h", - "login/ui/models/user_board_model.cc", - "login/ui/models/user_board_model.h", "login/ui/preloaded_web_view.cc", "login/ui/preloaded_web_view.h", "login/ui/preloaded_web_view_factory.cc", @@ -1450,6 +1448,24 @@ ] } +static_library("test_support") { + testonly = true + + sources = [ + "login/enrollment/enterprise_enrollment_helper_mock.cc", + "login/enrollment/enterprise_enrollment_helper_mock.h", + "login/enrollment/mock_enrollment_screen.cc", + "login/enrollment/mock_enrollment_screen.h", + "login/screens/mock_base_screen_delegate.cc", + "login/screens/mock_base_screen_delegate.h", + ] + + deps = [ + "//components/policy/proto", + "//testing/gmock", + ] +} + source_set("unit_tests") { testonly = true @@ -1576,6 +1592,7 @@ "login/auth/cryptohome_authenticator_unittest.cc", "login/easy_unlock/easy_unlock_challenge_wrapper_unittest.cc", "login/easy_unlock/easy_unlock_tpm_key_manager_unittest.cc", + "login/enrollment/enrollment_screen_unittest.cc", "login/error_screens_histogram_helper_unittest.cc", "login/existing_user_controller_auto_login_unittest.cc", "login/hwid_checker_unittest.cc", @@ -1719,6 +1736,7 @@ ":arc_test_support", ":attestation_proto", ":device_policy_proto", + ":test_support", "//ash/resources", "//components/drive", "//components/drive:test_support_chromeos",
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_data.cc b/chrome/browser/chromeos/app_mode/kiosk_app_data.cc index e354a72..8522d7b 100644 --- a/chrome/browser/chromeos/app_mode/kiosk_app_data.cc +++ b/chrome/browser/chromeos/app_mode/kiosk_app_data.cc
@@ -11,6 +11,7 @@ #include "base/json/json_writer.h" #include "base/macros.h" #include "base/memory/ref_counted_memory.h" +#include "base/task_scheduler/post_task.h" #include "base/threading/sequenced_worker_pool.h" #include "base/values.h" #include "chrome/browser/browser_process.h" @@ -426,8 +427,9 @@ dict_update->Remove(app_key, NULL); if (!icon_path_.empty()) { - BrowserThread::PostBlockingPoolTask( - FROM_HERE, + base::PostTaskWithTraits( + FROM_HERE, base::TaskTraits().MayBlock().WithPriority( + base::TaskPriority::BACKGROUND), base::Bind(base::IgnoreResult(&base::DeleteFile), icon_path_, false)); } }
diff --git a/chrome/browser/chromeos/arc/arc_auth_notification.cc b/chrome/browser/chromeos/arc/arc_auth_notification.cc index 02718a3..9560cd8 100644 --- a/chrome/browser/chromeos/arc/arc_auth_notification.cc +++ b/chrome/browser/chromeos/arc/arc_auth_notification.cc
@@ -4,6 +4,10 @@ #include "chrome/browser/chromeos/arc/arc_auth_notification.h" +#include <memory> +#include <string> +#include <utility> + #include "ash/common/system/chromeos/devicetype_utils.h" #include "base/macros.h" #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/chromeos/arc/arc_auth_service.cc b/chrome/browser/chromeos/arc/arc_auth_service.cc index 195c2ec..33a82f0 100644 --- a/chrome/browser/chromeos/arc/arc_auth_service.cc +++ b/chrome/browser/chromeos/arc/arc_auth_service.cc
@@ -7,20 +7,22 @@ #include <utility> #include "base/command_line.h" -#include "base/logging.h" #include "base/memory/ptr_util.h" #include "chrome/browser/chromeos/arc/arc_optin_uma.h" #include "chrome/browser/chromeos/arc/arc_session_manager.h" -#include "chrome/browser/chromeos/arc/auth/arc_auth_code_fetcher.h" +#include "chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.h" +#include "chrome/browser/chromeos/arc/auth/arc_auth_info_fetcher.h" #include "chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.h" #include "chrome/browser/chromeos/arc/auth/arc_manual_auth_code_fetcher.h" #include "chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.h" #include "chrome/browser/chromeos/arc/policy/arc_policy_util.h" +#include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chromeos/chromeos_switches.h" #include "components/arc/arc_bridge_service.h" #include "components/arc/arc_features.h" #include "components/arc/arc_util.h" +#include "components/user_manager/user_manager.h" #include "content/public/browser/browser_thread.h" namespace arc { @@ -86,25 +88,29 @@ account_info_callback_(account_info_callback) {} void Notify(bool is_enforced, - const std::string& auth_code, + const std::string& auth_info, mojom::ChromeAccountType account_type, bool is_managed) { switch (callback_type_) { case CallbackType::AUTH_CODE: DCHECK(!auth_callback_.is_null()); - auth_callback_.Run(auth_code, is_enforced); + auth_callback_.Run(auth_info, is_enforced); break; case CallbackType::AUTH_CODE_AND_ACCOUNT: DCHECK(!auth_account_callback_.is_null()); - auth_account_callback_.Run(auth_code, is_enforced, account_type); + auth_account_callback_.Run(auth_info, is_enforced, account_type); break; case CallbackType::ACCOUNT_INFO: DCHECK(!account_info_callback_.is_null()); mojom::AccountInfoPtr account_info = mojom::AccountInfo::New(); - if (!is_enforced) { - account_info->auth_code = base::nullopt; + if (account_type == + mojom::ChromeAccountType::ACTIVE_DIRECTORY_ACCOUNT) { + account_info->enrollment_token = auth_info; } else { - account_info->auth_code = auth_code; + if (!is_enforced) + account_info->auth_code = base::nullopt; + else + account_info->auth_code = auth_info; } account_info->account_type = account_type; account_info->is_managed = is_managed; @@ -223,14 +229,27 @@ // Hereafter asynchronous operation. Remember the notifier. notifier_ = std::move(notifier); + Profile* profile = ArcSessionManager::Get()->profile(); + const user_manager::User* user = nullptr; + if (profile) + user = chromeos::ProfileHelper::Get()->GetUserByProfile(profile); + if (user && user->IsActiveDirectoryUser()) { + // For Active Directory enrolled devices, we get an enrollment token for a + // managed Google Play account from DMServer. + fetcher_ = base::MakeUnique<ArcActiveDirectoryEnrollmentTokenFetcher>(); + fetcher_->Fetch(base::Bind(&ArcAuthService::OnEnrollmentTokenFetched, + weak_ptr_factory_.GetWeakPtr())); + return; + } + // For non-AD enrolled devices an auth code is fetched. if (IsArcKioskMode()) { // In Kiosk mode, use Robot auth code fetching. fetcher_ = base::MakeUnique<ArcRobotAuthCodeFetcher>(); } else if (base::FeatureList::IsEnabled(arc::kArcUseAuthEndpointFeature)) { // Optionally retrieve auth code in silent mode. + DCHECK(profile); fetcher_ = base::MakeUnique<ArcBackgroundAuthCodeFetcher>( - ArcSessionManager::Get()->profile(), - ArcSessionManager::Get()->auth_context()); + profile, ArcSessionManager::Get()->auth_context()); } else { // Report that silent auth code is not activated. All other states are // reported in ArcBackgroundAuthCodeFetcher. @@ -247,6 +266,22 @@ weak_ptr_factory_.GetWeakPtr())); } +void ArcAuthService::OnEnrollmentTokenFetched( + const std::string& enrollment_token) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + fetcher_.reset(); + + if (enrollment_token.empty()) { + ArcSessionManager::Get()->OnProvisioningFinished( + ProvisioningResult::CHROME_SERVER_COMMUNICATION_ERROR); + return; + } + + notifier_->Notify(true /*is_enforced*/, enrollment_token, + mojom::ChromeAccountType::ACTIVE_DIRECTORY_ACCOUNT, true); + notifier_.reset(); +} + void ArcAuthService::OnAuthCodeFetched(const std::string& auth_code) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); fetcher_.reset();
diff --git a/chrome/browser/chromeos/arc/arc_auth_service.h b/chrome/browser/chromeos/arc/arc_auth_service.h index 13080e1..b61927a 100644 --- a/chrome/browser/chromeos/arc/arc_auth_service.h +++ b/chrome/browser/chromeos/arc/arc_auth_service.h
@@ -17,7 +17,7 @@ namespace arc { -class ArcAuthCodeFetcher; +class ArcAuthInfoFetcher; // Implementation of ARC authorization. // TODO(hidehiko): Move to c/b/c/arc/auth with adding tests. @@ -61,7 +61,8 @@ void RequestAccountInfoInternal( std::unique_ptr<AccountInfoNotifier> account_info_notifier); - // Callback on auth_code fetched. + // Callbacks when auth info is fetched. + void OnEnrollmentTokenFetched(const std::string& enrollment_token); void OnAuthCodeFetched(const std::string& auth_code); // Called to let ARC container know the account info. @@ -70,7 +71,7 @@ mojo::Binding<mojom::AuthHost> binding_; std::unique_ptr<AccountInfoNotifier> notifier_; - std::unique_ptr<ArcAuthCodeFetcher> fetcher_; + std::unique_ptr<ArcAuthInfoFetcher> fetcher_; base::WeakPtrFactory<ArcAuthService> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/arc/arc_optin_uma.cc b/chrome/browser/chromeos/arc/arc_optin_uma.cc index f2ff20a..dfa391a 100644 --- a/chrome/browser/chromeos/arc/arc_optin_uma.cc +++ b/chrome/browser/chromeos/arc/arc_optin_uma.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/chromeos/arc/arc_optin_uma.h" +#include <string> + #include "base/metrics/histogram_macros.h" namespace arc {
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.cc b/chrome/browser/chromeos/arc/arc_session_manager.cc index ed2636b..0582a43 100644 --- a/chrome/browser/chromeos/arc/arc_session_manager.cc +++ b/chrome/browser/chromeos/arc/arc_session_manager.cc
@@ -260,7 +260,7 @@ // We don't expect ProvisioningResult::SUCCESS is reported twice or reported // after an error. DCHECK_NE(result, ProvisioningResult::SUCCESS); - // TODO (khmel): Consider changing LOG to NOTREACHED once we guaranty that + // TODO(khmel): Consider changing LOG to NOTREACHED once we guaranty that // no double message can happen in production. LOG(WARNING) << "Provisioning result was already reported. Ignoring " << "additional result " << static_cast<int>(result) << "."; @@ -417,9 +417,6 @@ DCHECK_EQ(State::NOT_INITIALIZED, state_); SetState(State::STOPPED); - PrefServiceSyncableFromProfile(profile_)->AddSyncedPrefObserver( - prefs::kArcEnabled, this); - context_.reset(new ArcAuthContext(profile_)); if (!g_disable_ui_for_testing || @@ -454,10 +451,6 @@ return; pref_service_syncable->RemoveObserver(this); - - if (IsArcEnabled()) - OnOptInPreferenceChanged(); - if (!g_disable_ui_for_testing && !base::CommandLine::ForCurrentProcess()->HasSwitch( chromeos::switches::kEnableArcOOBEOptIn) && @@ -481,7 +474,6 @@ sync_preferences::PrefServiceSyncable* pref_service_syncable = PrefServiceSyncableFromProfile(profile_); pref_service_syncable->RemoveObserver(this); - pref_service_syncable->RemoveSyncedPrefObserver(prefs::kArcEnabled, this); } pref_change_registrar_.RemoveAll(); context_.reset(); @@ -489,25 +481,6 @@ SetState(State::NOT_INITIALIZED); } -void ArcSessionManager::OnSyncedPrefChanged(const std::string& path, - bool from_sync) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - - // Update UMA only for local changes - if (!from_sync) { - const bool arc_enabled = - profile_->GetPrefs()->GetBoolean(prefs::kArcEnabled); - UpdateOptInActionUMA(arc_enabled ? OptInActionType::OPTED_IN - : OptInActionType::OPTED_OUT); - - if (!arc_enabled && !IsArcManaged()) { - ash::ShelfDelegate* shelf_delegate = GetShelfDelegate(); - if (shelf_delegate) - shelf_delegate->UnpinAppWithID(ArcSupportHost::kHostAppId); - } - } -} - void ArcSessionManager::StopArc() { if (state_ != State::STOPPED) { profile_->GetPrefs()->SetBoolean(prefs::kArcSignedIn, false); @@ -522,10 +495,22 @@ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(profile_); - // TODO(dspaid): Move code from OnSyncedPrefChanged into this method. - OnSyncedPrefChanged(prefs::kArcEnabled, IsArcManaged()); - const bool arc_enabled = IsArcEnabled(); + if (!IsArcManaged()) { + // Update UMA only for non-Managed cases. + UpdateOptInActionUMA(arc_enabled ? OptInActionType::OPTED_IN + : OptInActionType::OPTED_OUT); + + if (!arc_enabled) { + // Remove the pinned Play Store icon launcher in Shelf. + // This is only for non-Managed cases. In managed cases, it is expected + // to be "disabled" rather than "removed", so keep it here. + ash::ShelfDelegate* shelf_delegate = GetShelfDelegate(); + if (shelf_delegate) + shelf_delegate->UnpinAppWithID(ArcSupportHost::kHostAppId); + } + } + for (auto& observer : observer_list_) observer.OnArcOptInChanged(arc_enabled); @@ -613,7 +598,7 @@ // Need user's explicit Terms Of Service agreement. Prevent race condition // when ARC can be enabled before profile is synced. In last case // OnOptInPreferenceChanged is called twice. - // TODO (crbug.com/687185) + // TODO(crbug.com/687185): Remove the condition. if (state_ != State::SHOWING_TERMS_OF_SERVICE) StartTermsOfServiceNegotiation(); }
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.h b/chrome/browser/chromeos/arc/arc_session_manager.h index 0bb3697..0503f5f 100644 --- a/chrome/browser/chromeos/arc/arc_session_manager.h +++ b/chrome/browser/chromeos/arc/arc_session_manager.h
@@ -18,7 +18,6 @@ #include "components/arc/arc_session_observer.h" #include "components/prefs/pref_change_registrar.h" #include "components/sync_preferences/pref_service_syncable_observer.h" -#include "components/sync_preferences/synced_pref_observer.h" class ArcAppLauncher; class Profile; @@ -34,7 +33,7 @@ namespace arc { class ArcAndroidManagementChecker; -class ArcAuthCodeFetcher; +class ArcAuthInfoFetcher; class ArcAuthContext; class ArcSessionRunner; class ArcTermsOfServiceNegotiator; @@ -44,8 +43,7 @@ // LSO. It lives on the UI thread. class ArcSessionManager : public ArcSessionObserver, public ArcSupportHost::Observer, - public sync_preferences::PrefServiceSyncableObserver, - public sync_preferences::SyncedPrefObserver { + public sync_preferences::PrefServiceSyncableObserver { public: // Represents each State of ARC session. // NOT_INITIALIZED: represents the state that the Profile is not yet ready @@ -59,11 +57,8 @@ // state only for the first boot case (= opt-in case). The second time and // later the management check is running in parallel with ARC session // starting, and in such a case, State is ACTIVE, instead. - // FETCHING_CODE: Fetching an auth token. Similar to - // CHECKING_ANDROID_MANAGEMENT case, this is only for the first boot case. - // In re-auth flow (fetching an auth token while ARC is running), the - // State should be ACTIVE. - // TODO(hidehiko): Migrate into re-auth flow, then remove this state. + // REMOVING_DATA_DIR: When ARC is disabled, the data directory is removed. + // While removing is processed, ARC cannot be started. This is the state. // ACTIVE: ARC is running. // // State transition should be as follows: @@ -72,17 +67,12 @@ // ...(any)... -> NOT_INITIALIZED: when the Chrome is being shutdown. // ...(any)... -> STOPPED: on error. // - // In the first boot case (no OOBE case): + // In the first boot case: // STOPPED -> SHOWING_TERMS_OF_SERVICE: when arc.enabled preference is set. // SHOWING_TERMS_OF_SERVICE -> CHECKING_ANDROID_MANAGEMENT: when a user // agree with "Terms Of Service" - // CHECKING_ANDROID_MANAGEMENT -> FETCHING_CODE: when Android management - // check passes. - // FETCHING_CODE -> ACTIVE: when the auth token is successfully fetched. - // - // In the first boot case (OOBE case): - // STOPPED -> FETCHING_CODE: When arc.enabled preference is set. - // FETCHING_CODE -> ACTIVE: when the auth token is successfully fetched. + // CHECKING_ANDROID_MANAGEMENT -> ACTIVE: when the auth token is + // successfully fetched. // // In the second (or later) boot case: // STOPPED -> ACTIVE: when arc.enabled preference is checked that it is @@ -183,9 +173,6 @@ // sync_preferences::PrefServiceSyncableObserver void OnIsSyncingChanged() override; - // sync_preferences::SyncedPrefObserver - void OnSyncedPrefChanged(const std::string& path, bool from_sync) override; - // ArcSupportHost::Observer: void OnWindowClosed() override; void OnTermsAgreed(bool is_metrics_enabled, @@ -209,7 +196,7 @@ ArcSupportHost* support_host() { return support_host_.get(); } // TODO(hidehiko): Get rid of the getter by migration between ArcAuthContext - // and ArcAuthCodeFetcher. + // and ArcAuthInfoFetcher. ArcAuthContext* auth_context() { return context_.get(); } void StartArc();
diff --git a/chrome/browser/chromeos/arc/arc_util.cc b/chrome/browser/chromeos/arc/arc_util.cc index 5a0eef24..03dab5b1 100644 --- a/chrome/browser/chromeos/arc/arc_util.cc +++ b/chrome/browser/chromeos/arc/arc_util.cc
@@ -55,12 +55,17 @@ return false; } - // Do not allow for public session. Communicating with Play Store requires - // GAIA account. An exception is Kiosk mode, which uses different application - // install mechanism. cf) crbug.com/605545 + // Play Store requires an appropriate application install mechanism. Normal + // users do this through GAIA, but Kiosk and Active Directory users use + // different application install mechanism. ARC is not allowed otherwise + // (e.g. in public sessions). cf) crbug.com/605545 const user_manager::User* user = chromeos::ProfileHelper::Get()->GetUserByProfile(profile); - if ((!user || !user->HasGaiaAccount()) && !IsArcKioskMode()) { + const bool has_gaia_account = user && user->HasGaiaAccount(); + const bool is_arc_active_directory_user = + user && user->IsActiveDirectoryUser() && + IsArcAllowedForActiveDirectoryUsers(); + if (!has_gaia_account && !is_arc_active_directory_user && !IsArcKioskMode()) { VLOG(1) << "Users without GAIA accounts are not supported in ARC."; return false; }
diff --git a/chrome/browser/chromeos/arc/arc_util_unittest.cc b/chrome/browser/chromeos/arc/arc_util_unittest.cc index 7f6d8bc..1fe41ed8 100644 --- a/chrome/browser/chromeos/arc/arc_util_unittest.cc +++ b/chrome/browser/chromeos/arc/arc_util_unittest.cc
@@ -38,7 +38,8 @@ user_manager::UserType user_type = user_manager::USER_TYPE_REGULAR) : fake_user_manager_(fake_user_manager), account_id_(account_id) { switch (user_type) { - case user_manager::USER_TYPE_REGULAR: + case user_manager::USER_TYPE_REGULAR: // fallthrough + case user_manager::USER_TYPE_ACTIVE_DIRECTORY: LogIn(); break; case user_manager::USER_TYPE_ARC_KIOSK_APP: @@ -154,6 +155,30 @@ EXPECT_FALSE(IsArcAllowedForProfile(profile())); } +TEST_F(ChromeArcUtilTest, IsArcAllowedForProfile_ActiveDirectoryEnabled) { + base::CommandLine::ForCurrentProcess()->InitFromArgv( + {"", "--arc-availability=officially-supported-with-active-directory"}); + ScopedLogIn login( + GetFakeUserManager(), + AccountId::AdFromObjGuid("f04557de-5da2-40ce-ae9d-b8874d8da96e"), + user_manager::USER_TYPE_ACTIVE_DIRECTORY); + EXPECT_FALSE(chromeos::ProfileHelper::Get() + ->GetUserByProfile(profile()) + ->HasGaiaAccount()); + EXPECT_TRUE(IsArcAllowedForProfile(profile())); +} + +TEST_F(ChromeArcUtilTest, IsArcAllowedForProfile_ActiveDirectoryDisabled) { + ScopedLogIn login( + GetFakeUserManager(), + AccountId::AdFromObjGuid("f04557de-5da2-40ce-ae9d-b8874d8da96e"), + user_manager::USER_TYPE_ACTIVE_DIRECTORY); + EXPECT_FALSE(chromeos::ProfileHelper::Get() + ->GetUserByProfile(profile()) + ->HasGaiaAccount()); + EXPECT_FALSE(IsArcAllowedForProfile(profile())); +} + TEST_F(ChromeArcUtilTest, IsArcAllowedForProfile_Kiosk) { ScopedLogIn login(GetFakeUserManager(), AccountId::FromUserEmail(profile()->GetProfileUserName()),
diff --git a/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.cc b/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.cc new file mode 100644 index 0000000..d882cfcb --- /dev/null +++ b/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.cc
@@ -0,0 +1,106 @@ +// 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/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.h" + +#include <string> + +#include "base/bind.h" +#include "base/callback_helpers.h" +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" +#include "chrome/browser/chromeos/policy/dm_token_storage.h" +#include "chrome/browser/chromeos/settings/install_attributes.h" +#include "components/policy/core/common/cloud/device_management_service.h" +#include "net/url_request/url_request_context_getter.h" + +namespace { + +policy::DeviceManagementService* GetDeviceManagementService() { + policy::BrowserPolicyConnectorChromeOS* const connector = + g_browser_process->platform_part()->browser_policy_connector_chromeos(); + return connector->device_management_service(); +} + +std::string GetClientId() { + policy::BrowserPolicyConnectorChromeOS* const connector = + g_browser_process->platform_part()->browser_policy_connector_chromeos(); + return connector->GetInstallAttributes()->GetDeviceId(); +} + +} // namespace + +namespace arc { + +ArcActiveDirectoryEnrollmentTokenFetcher:: + ArcActiveDirectoryEnrollmentTokenFetcher() + : weak_ptr_factory_(this) {} + +ArcActiveDirectoryEnrollmentTokenFetcher:: + ~ArcActiveDirectoryEnrollmentTokenFetcher() = default; + +void ArcActiveDirectoryEnrollmentTokenFetcher::Fetch( + const FetchCallback& callback) { + DCHECK(callback_.is_null()); + callback_ = callback; + dm_token_storage_ = base::MakeUnique<policy::DMTokenStorage>( + g_browser_process->local_state()); + dm_token_storage_->RetrieveDMToken( + base::Bind(&ArcActiveDirectoryEnrollmentTokenFetcher::OnDMTokenAvailable, + weak_ptr_factory_.GetWeakPtr())); +} + +void ArcActiveDirectoryEnrollmentTokenFetcher::OnDMTokenAvailable( + const std::string& dm_token) { + DCHECK(!fetch_request_job_); + + if (dm_token.empty()) { + LOG(ERROR) << "Retrieving the DMToken failed."; + base::ResetAndReturn(&callback_).Run(std::string()); + return; + } + + policy::DeviceManagementService* service = GetDeviceManagementService(); + fetch_request_job_.reset( + service->CreateJob(policy::DeviceManagementRequestJob:: + TYPE_ACTIVE_DIRECTORY_ENROLL_PLAY_USER, + g_browser_process->system_request_context())); + + fetch_request_job_->SetDMToken(dm_token); + fetch_request_job_->SetClientID(GetClientId()); + fetch_request_job_->GetRequest() + ->mutable_active_directory_enroll_play_user_request(); + + fetch_request_job_->Start( + base::Bind(&ArcActiveDirectoryEnrollmentTokenFetcher:: + OnFetchEnrollmentTokenCompleted, + weak_ptr_factory_.GetWeakPtr())); +} + +void ArcActiveDirectoryEnrollmentTokenFetcher::OnFetchEnrollmentTokenCompleted( + policy::DeviceManagementStatus status, + int net_error, + const enterprise_management::DeviceManagementResponse& response) { + fetch_request_job_.reset(); + + if (status == policy::DM_STATUS_SUCCESS && + (!response.has_active_directory_enroll_play_user_response())) { + LOG(WARNING) << "Invalid Active Directory enroll Play user response."; + status = policy::DM_STATUS_RESPONSE_DECODING_ERROR; + } + + if (status != policy::DM_STATUS_SUCCESS) { + LOG(ERROR) << "Fetching an enrollment token failed. DM Status: " << status; + base::ResetAndReturn(&callback_).Run(std::string()); + return; + } + + base::ResetAndReturn(&callback_) + .Run(response.active_directory_enroll_play_user_response() + .enrollment_token()); +} + +} // namespace arc
diff --git a/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.h b/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.h new file mode 100644 index 0000000..c05a80f4 --- /dev/null +++ b/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.h
@@ -0,0 +1,57 @@ +// 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 CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_ACTIVE_DIRECTORY_ENROLLMENT_TOKEN_FETCHER_H_ +#define CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_ACTIVE_DIRECTORY_ENROLLMENT_TOKEN_FETCHER_H_ + +#include <memory> +#include <string> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/chromeos/arc/auth/arc_auth_info_fetcher.h" +#include "components/policy/core/common/cloud/cloud_policy_constants.h" + +namespace enterprise_management { +class DeviceManagementResponse; +} // namespace enterprise_management + +namespace policy { +class DeviceManagementRequestJob; +class DMTokenStorage; +} // namespace policy + +namespace arc { + +// This class is responsible to fetch an enrollment token for a new managed +// Google Play account when using ARC with Active Directory. +class ArcActiveDirectoryEnrollmentTokenFetcher : public ArcAuthInfoFetcher { + public: + ArcActiveDirectoryEnrollmentTokenFetcher(); + ~ArcActiveDirectoryEnrollmentTokenFetcher() override; + + // ArcAuthInfoFetcher: + void Fetch(const FetchCallback& callback) override; + + private: + void OnDMTokenAvailable(const std::string& dm_token); + void OnFetchEnrollmentTokenCompleted( + policy::DeviceManagementStatus status, + int net_error, + const enterprise_management::DeviceManagementResponse& response); + + std::unique_ptr<policy::DeviceManagementRequestJob> fetch_request_job_; + std::unique_ptr<policy::DMTokenStorage> dm_token_storage_; + FetchCallback callback_; + + base::WeakPtrFactory<ArcActiveDirectoryEnrollmentTokenFetcher> + weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(ArcActiveDirectoryEnrollmentTokenFetcher); +}; + +} // namespace arc + +#endif // CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_ACTIVE_DIRECTORY_ENROLLMENT_TOKEN_FETCHER_H_
diff --git a/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc b/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc new file mode 100644 index 0000000..ce952cf --- /dev/null +++ b/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc
@@ -0,0 +1,232 @@ +// 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 <memory> +#include <string> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/command_line.h" +#include "base/memory/ptr_util.h" +#include "base/run_loop.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/arc/arc_auth_service.h" +#include "chrome/browser/chromeos/arc/arc_session_manager.h" +#include "chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.h" +#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h" +#include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h" +#include "chrome/browser/chromeos/policy/dm_token_storage.h" +#include "chrome/browser/policy/cloud/test_request_interceptor.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/fake_cryptohome_client.h" +#include "components/arc/arc_util.h" +#include "components/policy/core/common/cloud/device_management_service.h" +#include "components/policy/core/common/policy_switches.h" +#include "content/public/browser/browser_thread.h" +#include "net/base/network_delegate.h" +#include "net/base/upload_bytes_element_reader.h" +#include "net/base/upload_data_stream.h" +#include "net/base/url_util.h" +#include "net/http/http_request_headers.h" +#include "net/url_request/url_request.h" +#include "net/url_request/url_request_test_job.h" +#include "testing/gtest/include/gtest/gtest.h" + +constexpr char kFakeDmToken[] = "fake-dm-token"; +constexpr char kFakeEnrollmentToken[] = "fake-enrollment-token"; +constexpr char kFakeGuid[] = "f04557de-5da2-40ce-ae9d-b8874d8da96e"; + +// JobCallback for the interceptor. +net::URLRequestJob* ResponseJob(net::URLRequest* request, + net::NetworkDelegate* network_delegate) { + // Check the operation. + std::string request_type; + EXPECT_TRUE( + net::GetValueForKeyInQuery(request->url(), "request", &request_type)); + EXPECT_EQ("active_directory_enroll_play_user", request_type); + + // Check content of request. + const net::UploadDataStream* upload = request->get_upload(); + EXPECT_TRUE(upload); + EXPECT_TRUE(upload->GetElementReaders()); + EXPECT_EQ(1u, upload->GetElementReaders()->size()); + EXPECT_TRUE((*upload->GetElementReaders())[0]->AsBytesReader()); + + const net::UploadBytesElementReader* bytes_reader = + (*upload->GetElementReaders())[0]->AsBytesReader(); + + enterprise_management::DeviceManagementRequest parsed_request; + EXPECT_TRUE(parsed_request.ParseFromArray(bytes_reader->bytes(), + bytes_reader->length())); + EXPECT_TRUE(parsed_request.has_active_directory_enroll_play_user_request()); + + // Check the DMToken. + net::HttpRequestHeaders request_headers = request->extra_request_headers(); + std::string value; + EXPECT_TRUE(request_headers.GetHeader("Authorization", &value)); + EXPECT_EQ("GoogleDMToken token=" + std::string(kFakeDmToken), value); + + // Response contains the enrollment token. + enterprise_management::DeviceManagementResponse response; + response.mutable_active_directory_enroll_play_user_response() + ->set_enrollment_token(kFakeEnrollmentToken); + std::string response_data; + EXPECT_TRUE(response.SerializeToString(&response_data)); + + return new net::URLRequestTestJob(request, network_delegate, + net::URLRequestTestJob::test_headers(), + response_data, true); +} + +class ArcActiveDirectoryEnrollmentTokenFetcherBrowserTest + : public InProcessBrowserTest { + protected: + ArcActiveDirectoryEnrollmentTokenFetcherBrowserTest() = default; + ~ArcActiveDirectoryEnrollmentTokenFetcherBrowserTest() override = default; + + void SetUpCommandLine(base::CommandLine* command_line) override { + InProcessBrowserTest::SetUpCommandLine(command_line); + command_line->AppendSwitchASCII(policy::switches::kDeviceManagementUrl, + "http://localhost"); + arc::SetArcAvailableCommandLineForTesting(command_line); + } + + void SetUpInProcessBrowserTestFixture() override { + // Set fake cryptohome, because we want to fail DMToken retrieval + auto cryptohome_client = base::MakeUnique<chromeos::FakeCryptohomeClient>(); + fake_cryptohome_client_ = cryptohome_client.get(); + chromeos::DBusThreadManager::GetSetterForTesting()->SetCryptohomeClient( + std::move(cryptohome_client)); + } + + void SetUpOnMainThread() override { + interceptor_ = base::MakeUnique<policy::TestRequestInterceptor>( + "localhost", content::BrowserThread::GetTaskRunnerForThread( + content::BrowserThread::IO)); + + user_manager_enabler_ = + base::MakeUnique<chromeos::ScopedUserManagerEnabler>( + new chromeos::FakeChromeUserManager()); + + const AccountId account_id(AccountId::AdFromObjGuid(kFakeGuid)); + GetFakeUserManager()->LoginUser(account_id); + } + + void StoreCorrectDmToken() { + fake_cryptohome_client_->set_system_salt( + chromeos::FakeCryptohomeClient::GetStubSystemSalt()); + fake_cryptohome_client_->SetServiceIsAvailable(true); + // Store a fake DM token. + base::RunLoop run_loop; + auto dm_token_storage = base::MakeUnique<policy::DMTokenStorage>( + g_browser_process->local_state()); + dm_token_storage->StoreDMToken( + kFakeDmToken, base::Bind( + [](base::RunLoop* run_loop, bool success) { + EXPECT_TRUE(success); + run_loop->Quit(); + }, + &run_loop)); + // Because the StoreDMToken() operation interacts with the I/O thread, + // RunUntilIdle() won't work here. Instead, use Run() and Quit() explicitly + // in the callback. + run_loop.Run(); + } + + void FailDmToken() { + fake_cryptohome_client_->set_system_salt(std::vector<uint8_t>()); + fake_cryptohome_client_->SetServiceIsAvailable(true); + } + + void TearDownOnMainThread() override { + user_manager_enabler_.reset(); + interceptor_.reset(); + } + + chromeos::FakeChromeUserManager* GetFakeUserManager() const { + return static_cast<chromeos::FakeChromeUserManager*>( + user_manager::UserManager::Get()); + } + + policy::TestRequestInterceptor* interceptor() { return interceptor_.get(); } + + static void FetchEnrollmentToken( + arc::ArcActiveDirectoryEnrollmentTokenFetcher* fetcher, + std::string* output_enrollment_token) { + base::RunLoop run_loop; + fetcher->Fetch(base::Bind( + [](std::string* output_enrollment_token, base::RunLoop* run_loop, + const std::string& enrollment_token) { + *output_enrollment_token = enrollment_token; + run_loop->Quit(); + }, + output_enrollment_token, &run_loop)); + // Because the Fetch() operation needs to interact with other threads, + // RunUntilIdle() won't work here. Instead, use Run() and Quit() explicitly + // in the callback. + run_loop.Run(); + } + + private: + std::unique_ptr<policy::TestRequestInterceptor> interceptor_; + std::unique_ptr<chromeos::ScopedUserManagerEnabler> user_manager_enabler_; + // DBusThreadManager owns this. + chromeos::FakeCryptohomeClient* fake_cryptohome_client_; + + DISALLOW_COPY_AND_ASSIGN(ArcActiveDirectoryEnrollmentTokenFetcherBrowserTest); +}; + +IN_PROC_BROWSER_TEST_F(ArcActiveDirectoryEnrollmentTokenFetcherBrowserTest, + RequestAccountInfoSuccess) { + interceptor()->PushJobCallback(base::Bind(&ResponseJob)); + + // Retrieving the DM token will succeed. + StoreCorrectDmToken(); + + std::string enrollment_token; + auto token_fetcher = + base::MakeUnique<arc::ArcActiveDirectoryEnrollmentTokenFetcher>(); + FetchEnrollmentToken(token_fetcher.get(), &enrollment_token); + EXPECT_EQ(kFakeEnrollmentToken, enrollment_token); +} + +IN_PROC_BROWSER_TEST_F(ArcActiveDirectoryEnrollmentTokenFetcherBrowserTest, + DmTokenRetrievalFailed) { + interceptor()->PushJobCallback(base::Bind( + [](net::URLRequest*, net::NetworkDelegate*) -> net::URLRequestJob* { + ADD_FAILURE() << "DMServer called when not expected"; + return nullptr; + })); + + // Retrieving the DM token will fail. + FailDmToken(); + + // We expect enrollment_token is empty in this case. So initialize with + // non-empty value. + std::string enrollment_token = "NOT-YET-FETCHED"; + auto token_fetcher = + base::MakeUnique<arc::ArcActiveDirectoryEnrollmentTokenFetcher>(); + FetchEnrollmentToken(token_fetcher.get(), &enrollment_token); + + EXPECT_EQ(std::string(), enrollment_token); +} + +IN_PROC_BROWSER_TEST_F(ArcActiveDirectoryEnrollmentTokenFetcherBrowserTest, + RequestAccountInfoError) { + interceptor()->PushJobCallback( + policy::TestRequestInterceptor::BadRequestJob()); + + // Retrieving the DM token will succeed. + StoreCorrectDmToken(); + + // We expect enrollment_token is empty in this case. So initialize with + // non-empty value. + std::string enrollment_token = "NOT-YET-FETCHED"; + auto token_fetcher = + base::MakeUnique<arc::ArcActiveDirectoryEnrollmentTokenFetcher>(); + FetchEnrollmentToken(token_fetcher.get(), &enrollment_token); + + EXPECT_EQ(std::string(), enrollment_token); +}
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_code_fetcher.h b/chrome/browser/chromeos/arc/auth/arc_auth_code_fetcher.h deleted file mode 100644 index 7f9770e..0000000 --- a/chrome/browser/chromeos/arc/auth/arc_auth_code_fetcher.h +++ /dev/null
@@ -1,30 +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 CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_AUTH_CODE_FETCHER_H_ -#define CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_AUTH_CODE_FETCHER_H_ - -#include <string> - -#include "base/callback.h" - -namespace arc { - -// Interface to implement auth_code fetching. -class ArcAuthCodeFetcher { - public: - virtual ~ArcAuthCodeFetcher() = default; - - // Fetches the |auth_code|. On success, |callback| is called with the - // fetched |auth_code|. Otherwise, |callback| is called with empty string. - // Fetch() should be called once par instance, and it is expected that - // the inflight operation is cancelled without calling the |callback| - // when the instance is deleted. - using FetchCallback = base::Callback<void(const std::string& auth_code)>; - virtual void Fetch(const FetchCallback& callback) = 0; -}; - -} // namespace arc - -#endif // CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_AUTH_CODE_FETCHER_H_
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_info_fetcher.h b/chrome/browser/chromeos/arc/auth/arc_auth_info_fetcher.h new file mode 100644 index 0000000..0de6614 --- /dev/null +++ b/chrome/browser/chromeos/arc/auth/arc_auth_info_fetcher.h
@@ -0,0 +1,31 @@ +// 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 CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_AUTH_INFO_FETCHER_H_ +#define CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_AUTH_INFO_FETCHER_H_ + +#include <string> + +#include "base/callback.h" + +namespace arc { + +// Interface to implement auth_code or enrollment token fetching. +class ArcAuthInfoFetcher { + public: + virtual ~ArcAuthInfoFetcher() = default; + + // Fetches the auth code or the enrollment token. On success, |callback| is + // called with the fetched |auth_info|. Otherwise, |callback| is called with + // empty string. + // Fetch() should be called once per instance, and it is expected that + // the inflight operation is cancelled without calling the |callback| + // when the instance is deleted. + using FetchCallback = base::Callback<void(const std::string& auth_info)>; + virtual void Fetch(const FetchCallback& callback) = 0; +}; + +} // namespace arc + +#endif // CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_AUTH_INFO_FETCHER_H_
diff --git a/chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.h b/chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.h index 0463868..dbb5d35 100644 --- a/chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.h +++ b/chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.h
@@ -13,7 +13,7 @@ #include "base/memory/weak_ptr.h" #include "chrome/browser/chromeos/arc/arc_auth_context.h" #include "chrome/browser/chromeos/arc/arc_optin_uma.h" -#include "chrome/browser/chromeos/arc/auth/arc_auth_code_fetcher.h" +#include "chrome/browser/chromeos/arc/auth/arc_auth_info_fetcher.h" #include "google_apis/gaia/oauth2_token_service.h" #include "net/url_request/url_fetcher_delegate.h" @@ -28,14 +28,14 @@ // The instance is not reusable, so for each Fetch(), the instance must be // re-created. Deleting the instance cancels inflight operation. -class ArcBackgroundAuthCodeFetcher : public ArcAuthCodeFetcher, +class ArcBackgroundAuthCodeFetcher : public ArcAuthInfoFetcher, public OAuth2TokenService::Consumer, public net::URLFetcherDelegate { public: ArcBackgroundAuthCodeFetcher(Profile* profile, ArcAuthContext* context); ~ArcBackgroundAuthCodeFetcher() override; - // ArcAuthCodeFetcher: + // ArcAuthInfoFetcher: void Fetch(const FetchCallback& callback) override; private:
diff --git a/chrome/browser/chromeos/arc/auth/arc_manual_auth_code_fetcher.h b/chrome/browser/chromeos/arc/auth/arc_manual_auth_code_fetcher.h index 7975dcc..2382759 100644 --- a/chrome/browser/chromeos/arc/auth/arc_manual_auth_code_fetcher.h +++ b/chrome/browser/chromeos/arc/auth/arc_manual_auth_code_fetcher.h
@@ -10,7 +10,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/chromeos/arc/arc_support_host.h" -#include "chrome/browser/chromeos/arc/auth/arc_auth_code_fetcher.h" +#include "chrome/browser/chromeos/arc/auth/arc_auth_info_fetcher.h" namespace net { class URLRequestContextGetter; @@ -22,7 +22,7 @@ // Implements the auth token fetching procedure with user's "SIGN IN" button // click. -class ArcManualAuthCodeFetcher : public ArcAuthCodeFetcher, +class ArcManualAuthCodeFetcher : public ArcAuthInfoFetcher, public ArcSupportHost::Observer { public: ArcManualAuthCodeFetcher(ArcAuthContext* context,
diff --git a/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.h b/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.h index fdf02d7..c7ee265c 100644 --- a/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.h +++ b/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.h
@@ -10,7 +10,7 @@ #include "base/callback.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "chrome/browser/chromeos/arc/auth/arc_auth_code_fetcher.h" +#include "chrome/browser/chromeos/arc/auth/arc_auth_info_fetcher.h" #include "components/policy/core/common/cloud/cloud_policy_constants.h" namespace enterprise_management { @@ -25,12 +25,12 @@ // This class is responsible to fetch auth code for robot account. Robot auth // code is used for creation an account on Android side in ARC kiosk mode. -class ArcRobotAuthCodeFetcher : public ArcAuthCodeFetcher { +class ArcRobotAuthCodeFetcher : public ArcAuthInfoFetcher { public: ArcRobotAuthCodeFetcher(); ~ArcRobotAuthCodeFetcher() override; - // ArcAuthCodeFetcher: + // ArcAuthInfoFetcher: void Fetch(const FetchCallback& callback) override; private:
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_async_file_util.h b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_async_file_util.h index 550c1ba..2bcf74f 100644 --- a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_async_file_util.h +++ b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_async_file_util.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_CHROMEOS_ARC_FILEAPI_ARC_CONTENT_FILE_SYSTEM_ASYNC_FILE_UTIL_H_ #define CHROME_BROWSER_CHROMEOS_ARC_FILEAPI_ARC_CONTENT_FILE_SYSTEM_ASYNC_FILE_UTIL_H_ +#include <memory> + #include "storage/browser/fileapi/async_file_util.h" namespace arc {
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_url_util.h b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_url_util.h index b787f39..1a49c78 100644 --- a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_url_util.h +++ b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_url_util.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_CHROMEOS_ARC_FILEAPI_ARC_CONTENT_FILE_SYSTEM_URL_UTIL_H_ #define CHROME_BROWSER_CHROMEOS_ARC_FILEAPI_ARC_CONTENT_FILE_SYSTEM_URL_UTIL_H_ +#include <string> + #include "base/files/file_path.h" #include "url/gurl.h"
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_async_file_util.h b/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_async_file_util.h index be0beb11..32b4a196 100644 --- a/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_async_file_util.h +++ b/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_async_file_util.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_CHROMEOS_ARC_FILEAPI_ARC_DOCUMENTS_PROVIDER_ASYNC_FILE_UTIL_H_ #define CHROME_BROWSER_CHROMEOS_ARC_FILEAPI_ARC_DOCUMENTS_PROVIDER_ASYNC_FILE_UTIL_H_ +#include <memory> + #include "base/callback.h" #include "base/macros.h" #include "storage/browser/fileapi/async_file_util.h"
diff --git a/chrome/browser/chromeos/arc/policy/arc_policy_bridge.h b/chrome/browser/chromeos/arc/policy/arc_policy_bridge.h index 2e1c0854..4966c0a 100644 --- a/chrome/browser/chromeos/arc/policy/arc_policy_bridge.h +++ b/chrome/browser/chromeos/arc/policy/arc_policy_bridge.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_CHROMEOS_ARC_POLICY_ARC_POLICY_BRIDGE_H_ #define CHROME_BROWSER_CHROMEOS_ARC_POLICY_ARC_POLICY_BRIDGE_H_ +#include <memory> #include <string> #include "base/macros.h"
diff --git a/chrome/browser/chromeos/external_protocol_dialog.cc b/chrome/browser/chromeos/external_protocol_dialog.cc index 383e4d80..16e4f43 100644 --- a/chrome/browser/chromeos/external_protocol_dialog.cc +++ b/chrome/browser/chromeos/external_protocol_dialog.cc
@@ -73,7 +73,7 @@ } bool ExternalProtocolDialog::Accept() { - ExternalProtocolHandler::RecordMetrics( + ExternalProtocolHandler::RecordCheckboxStateMetrics( message_box_view_->IsCheckBoxSelected()); // Returning true closes the dialog.
diff --git a/chrome/browser/chromeos/hats/hats_dialog.cc b/chrome/browser/chromeos/hats/hats_dialog.cc index 618ece2..dc9ae4d 100644 --- a/chrome/browser/chromeos/hats/hats_dialog.cc +++ b/chrome/browser/chromeos/hats/hats_dialog.cc
@@ -6,6 +6,7 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" +#include "base/task_scheduler/post_task.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/browser_dialogs.h" #include "chrome/common/pref_names.h" @@ -14,7 +15,6 @@ #include "chromeos/system/version_loader.h" #include "components/prefs/pref_service.h" #include "components/version_info/version_info.h" -#include "content/public/browser/browser_thread.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/geometry/size.h" @@ -124,8 +124,9 @@ std::unique_ptr<HatsDialog> hats_dialog(new HatsDialog); - base::PostTaskAndReplyWithResult( - content::BrowserThread::GetBlockingPool(), FROM_HERE, + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, base::TaskTraits().MayBlock().WithPriority( + base::TaskPriority::BACKGROUND), base::Bind(&GetFormattedSiteContext, user_locale, kDeviceInfoStopKeyword), base::Bind(&HatsDialog::Show, base::Passed(&hats_dialog), is_google_account ? kGooglerSiteID : kSiteID));
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc index 9cd43a2..c9d7ab0c 100644 --- a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc +++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
@@ -130,6 +130,8 @@ enabled_extension_imes = other.enabled_extension_imes; extra_input_methods = other.extra_input_methods; menu_activated = other.menu_activated; + allowed_keyboard_layout_input_method_ids = + other.allowed_keyboard_layout_input_method_ids; } bool InputMethodManagerImpl::StateImpl::IsActive() const { @@ -255,7 +257,12 @@ for (size_t i = 0; i < initial_layouts.size(); ++i) { if (manager_->util_.IsValidInputMethodId(initial_layouts[i])) { if (manager_->IsLoginKeyboard(initial_layouts[i])) { - layouts.push_back(initial_layouts[i]); + if (IsInputMethodAllowed(initial_layouts[i])) { + layouts.push_back(initial_layouts[i]); + } else { + DVLOG(1) << "EnableLoginLayouts: ignoring layout disallowd by policy:" + << initial_layouts[i]; + } } else { DVLOG(1) << "EnableLoginLayouts: ignoring non-login initial keyboard layout:" @@ -272,8 +279,10 @@ const std::string& candidate = candidates[i]; // Not efficient, but should be fine, as the two vectors are very // short (2-5 items). - if (!Contains(layouts, candidate) && manager_->IsLoginKeyboard(candidate)) + if (!Contains(layouts, candidate) && manager_->IsLoginKeyboard(candidate) && + IsInputMethodAllowed(candidate)) { layouts.push_back(candidate); + } } manager_->MigrateInputMethods(&layouts); @@ -334,6 +343,11 @@ bool InputMethodManagerImpl::StateImpl::EnableInputMethodImpl( const std::string& input_method_id, std::vector<std::string>* new_active_input_method_ids) const { + if (!IsInputMethodAllowed(input_method_id)) { + DVLOG(1) << "EnableInputMethod: " << input_method_id << " is not allowed."; + return false; + } + DCHECK(new_active_input_method_ids); if (!manager_->util_.IsValidInputMethodId(input_method_id)) { DVLOG(1) << "EnableInputMethod: Invalid ID: " << input_method_id; @@ -395,6 +409,54 @@ return true; } +bool InputMethodManagerImpl::StateImpl::SetAllowedInputMethods( + const std::vector<std::string>& new_allowed_input_method_ids) { + allowed_keyboard_layout_input_method_ids.clear(); + for (auto input_method_id : new_allowed_input_method_ids) { + std::string migrated_id = + manager_->util_.MigrateInputMethod(input_method_id); + if (manager_->util_.IsValidInputMethodId(migrated_id)) { + allowed_keyboard_layout_input_method_ids.push_back(migrated_id); + } + } + + if (allowed_keyboard_layout_input_method_ids.empty()) { + // None of the passed input methods were valid, so allow everything. + return false; + } + + // Enable all allowed keyboard layout input methods. Leave all non-keyboard + // input methods enabled. + std::vector<std::string> new_active_input_method_ids( + allowed_keyboard_layout_input_method_ids); + for (auto active_input_method_id : active_input_method_ids) { + if (!manager_->util_.IsKeyboardLayout(active_input_method_id)) + new_active_input_method_ids.push_back(active_input_method_id); + } + return ReplaceEnabledInputMethods(new_active_input_method_ids); +} + +const std::vector<std::string>& +InputMethodManagerImpl::StateImpl::GetAllowedInputMethods() { + return allowed_keyboard_layout_input_method_ids; +} + +bool InputMethodManagerImpl::StateImpl::IsInputMethodAllowed( + const std::string& input_method_id) const { + // Every input method is allowed if SetAllowedKeyboardLayoutInputMethods has + // not been called. + if (allowed_keyboard_layout_input_method_ids.empty()) + return true; + + // We only restrict keyboard layouts. + if (!manager_->util_.IsKeyboardLayout(input_method_id)) + return true; + + return Contains(allowed_keyboard_layout_input_method_ids, input_method_id) || + Contains(allowed_keyboard_layout_input_method_ids, + manager_->util_.MigrateInputMethod(input_method_id)); +} + void InputMethodManagerImpl::StateImpl::ChangeInputMethod( const std::string& input_method_id, bool show_message) {
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.h b/chrome/browser/chromeos/input_method/input_method_manager_impl.h index cfd8fc8..cf75325 100644 --- a/chrome/browser/chromeos/input_method/input_method_manager_impl.h +++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.h
@@ -113,6 +113,10 @@ bool ReplaceEnabledInputMethods( const std::vector<std::string>& new_active_input_method_ids) override; + bool SetAllowedInputMethods( + const std::vector<std::string>& new_allowed_input_method_ids) override; + const std::vector<std::string>& GetAllowedInputMethods() override; + // ------------------------- Data members. Profile* const profile; @@ -123,6 +127,9 @@ // The active input method ids cache. std::vector<std::string> active_input_method_ids; + // The allowed keyboard layout input methods (e.g. by policy). + std::vector<std::string> allowed_keyboard_layout_input_method_ids; + // The pending input method id for delayed 3rd party IME enabling. std::string pending_input_method_id; @@ -141,6 +148,13 @@ protected: friend base::RefCounted<chromeos::input_method::InputMethodManager::State>; ~StateImpl() override; + + private: + // Retruns true if the passed input method is allowed. By default, all input + // methods are allowed. After SetAllowedKeyboardLayoutInputMethods was + // called, the passed keyboard layout input methods are allowed and all + // non-keyboard input methods remain to be allowed. + bool IsInputMethodAllowed(const std::string& input_method_id) const; }; // Constructs an InputMethodManager instance. The client is responsible for
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc index 29944c6..524a3492 100644 --- a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc +++ b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
@@ -24,6 +24,7 @@ #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile_manager.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/accelerators/accelerator.h" #include "ui/base/ime/chromeos/extension_ime_util.h" @@ -1455,5 +1456,96 @@ EXPECT_EQ(default_url, keyboard::GetOverrideContentUrl()); } +TEST_F(InputMethodManagerImplTest, AllowedKeyboardLayoutsValid) { + InitComponentExtension(); + + // First, setup xkb:fr::fra input method + std::string original_input_method(ImeIdFromEngineId("xkb:fr::fra")); + ASSERT_TRUE( + manager_->GetActiveIMEState()->EnableInputMethod(original_input_method)); + manager_->GetActiveIMEState()->ChangeInputMethod(original_input_method, + false); + EXPECT_THAT(manager_->GetActiveIMEState()->GetCurrentInputMethod().id(), + original_input_method); + + // Only allow xkb:us::eng + std::vector<std::string> allowed = {"xkb:us::eng"}; + EXPECT_TRUE(manager_->GetActiveIMEState()->SetAllowedInputMethods(allowed)); + EXPECT_THAT(manager_->GetActiveIMEState()->GetActiveInputMethodIds(), + testing::ElementsAre(ImeIdFromEngineId("xkb:us::eng"))); + EXPECT_THAT(manager_->GetActiveIMEState()->GetCurrentInputMethod().id(), + ImeIdFromEngineId("xkb:us::eng")); + EXPECT_THAT(manager_->GetActiveIMEState()->GetAllowedInputMethods(), + testing::ElementsAre(ImeIdFromEngineId("xkb:us::eng"))); +} + +TEST_F(InputMethodManagerImplTest, AllowedKeyboardLayoutsInvalid) { + InitComponentExtension(); + + // First, setup xkb:fr::fra input method + std::string original_input_method(ImeIdFromEngineId("xkb:fr::fra")); + ASSERT_TRUE( + manager_->GetActiveIMEState()->EnableInputMethod(original_input_method)); + manager_->GetActiveIMEState()->ChangeInputMethod(original_input_method, + false); + EXPECT_THAT(manager_->GetActiveIMEState()->GetCurrentInputMethod().id(), + original_input_method); + + // Only allow xkb:us::eng + std::vector<std::string> allowed = {"invalid_input_method"}; + EXPECT_FALSE(manager_->GetActiveIMEState()->SetAllowedInputMethods(allowed)); + EXPECT_THAT(manager_->GetActiveIMEState()->GetCurrentInputMethod().id(), + original_input_method); + EXPECT_THAT(manager_->GetActiveIMEState()->GetAllowedInputMethods(), + testing::IsEmpty()); +} + +TEST_F(InputMethodManagerImplTest, AllowedKeyboardLayoutsValidAndInvalid) { + InitComponentExtension(); + + // First, enable xkb:fr::fra and xkb:de::ger + std::string original_input_method_1(ImeIdFromEngineId("xkb:fr::fra")); + std::string original_input_method_2(ImeIdFromEngineId("xkb:de::ger")); + ASSERT_TRUE(manager_->GetActiveIMEState()->EnableInputMethod( + original_input_method_1)); + ASSERT_TRUE(manager_->GetActiveIMEState()->EnableInputMethod( + original_input_method_2)); + manager_->GetActiveIMEState()->ChangeInputMethod(original_input_method_1, + false); + + // Allow xkb:fr::fra and an invalid input method id. The invalid id should be + // ignored. + std::vector<std::string> allowed = {original_input_method_1, + "invalid_input_method"}; + EXPECT_TRUE(manager_->GetActiveIMEState()->SetAllowedInputMethods(allowed)); + EXPECT_THAT(manager_->GetActiveIMEState()->GetCurrentInputMethod().id(), + original_input_method_1); + EXPECT_THAT(manager_->GetActiveIMEState()->GetAllowedInputMethods(), + testing::ElementsAre(original_input_method_1)); + + // Try to re-enable xkb:de::ger + EXPECT_FALSE(manager_->GetActiveIMEState()->EnableInputMethod( + original_input_method_2)); +} + +TEST_F(InputMethodManagerImplTest, AllowedKeyboardLayoutsAndExtensions) { + InitComponentExtension(); + + EXPECT_TRUE(manager_->GetActiveIMEState()->EnableInputMethod( + ImeIdFromEngineId(kNaclMozcJpId))); + EXPECT_TRUE(manager_->GetActiveIMEState()->EnableInputMethod( + ImeIdFromEngineId("xkb:fr::fra"))); + + std::vector<std::string> allowed = {"xkb:us::eng"}; + EXPECT_TRUE(manager_->GetActiveIMEState()->SetAllowedInputMethods(allowed)); + + EXPECT_TRUE(manager_->GetActiveIMEState()->EnableInputMethod( + ImeIdFromEngineId(kNaclMozcUsId))); + EXPECT_THAT(manager_->GetActiveIMEState()->GetActiveInputMethodIds(), + testing::ElementsAre(ImeIdFromEngineId("xkb:us::eng"), + ImeIdFromEngineId(kNaclMozcJpId), + ImeIdFromEngineId(kNaclMozcUsId))); +} + } // namespace input_method } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc index 010592b0..4df30241 100644 --- a/chrome/browser/chromeos/login/chrome_restart_request.cc +++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -180,7 +180,7 @@ app_list::switches::kDisableSyncAppList, app_list::switches::kEnableSyncAppList, ash::switches::kAshEnableTouchView, - ash::switches::kAshEnablePalette, + ash::switches::kAshForceEnablePalette, ash::switches::kAshEnablePaletteOnAllDisplays, ash::switches::kAshTouchHud, ash::switches::kAuraLegacyPowerButton,
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc b/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc index 6652c6b..7ea06de 100644 --- a/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc +++ b/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc
@@ -52,6 +52,19 @@ const char * const kMetricEnrollmentTimeSuccess = "Enterprise.EnrollmentTime.Success"; +// Retry policy constants. +constexpr int kInitialDelayMS = 4 * 1000; // 4 seconds +constexpr double kMultiplyFactor = 1.5; +constexpr double kJitterFactor = 0.1; // +/- 10% jitter +constexpr int64_t kMaxDelayMS = 8 * 60 * 1000; // 8 minutes + +// Helper function. Returns true if we are using Hands Off Enrollment. +bool UsingHandsOffEnrollment() { + return policy::DeviceCloudPolicyManagerChromeOS:: + GetZeroTouchEnrollmentMode() == + policy::ZeroTouchEnrollmentMode::HANDS_OFF; +} + } // namespace namespace chromeos { @@ -66,7 +79,16 @@ EnrollmentScreenActor* actor) : BaseScreen(base_screen_delegate, OobeScreen::SCREEN_OOBE_ENROLLMENT), actor_(actor), - weak_ptr_factory_(this) {} + weak_ptr_factory_(this) { + retry_policy_.num_errors_to_ignore = 0; + retry_policy_.initial_delay_ms = kInitialDelayMS; + retry_policy_.multiply_factor = kMultiplyFactor; + retry_policy_.jitter_factor = kJitterFactor; + retry_policy_.maximum_backoff_ms = kMaxDelayMS; + retry_policy_.entry_lifetime_ms = -1; + retry_policy_.always_use_initial_delay = true; + retry_backoff_.reset(new net::BackoffEntry(&retry_policy_)); +} EnrollmentScreen::~EnrollmentScreen() { DCHECK(!enrollment_helper_ || g_browser_process->IsShuttingDown()); @@ -190,6 +212,22 @@ } void EnrollmentScreen::OnRetry() { + retry_task_.Cancel(); + ProcessRetry(); +} + +void EnrollmentScreen::AutomaticRetry() { + retry_backoff_->InformOfRequest(false); + retry_task_.Reset(base::Bind(&EnrollmentScreen::ProcessRetry, + weak_ptr_factory_.GetWeakPtr())); + + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, retry_task_.callback(), retry_backoff_->GetTimeUntilRelease()); +} + +void EnrollmentScreen::ProcessRetry() { + ++num_retries_; + LOG(WARNING) << "Enrollment retry " << num_retries_; Show(); } @@ -243,16 +281,21 @@ // based enrollment and we have a fallback authentication, show it. if (status.status() == policy::EnrollmentStatus::REGISTRATION_FAILED && status.client_status() == policy::DM_STATUS_SERVICE_DEVICE_NOT_FOUND && - current_auth_ == AUTH_ATTESTATION && AdvanceToNextAuth()) + current_auth_ == AUTH_ATTESTATION && AdvanceToNextAuth()) { Show(); - else + } else { actor_->ShowEnrollmentStatus(status); + if (UsingHandsOffEnrollment()) + AutomaticRetry(); + } } void EnrollmentScreen::OnOtherError( EnterpriseEnrollmentHelper::OtherError error) { RecordEnrollmentErrorMetrics(); actor_->ShowOtherError(error); + if (UsingHandsOffEnrollment()) + AutomaticRetry(); } void EnrollmentScreen::OnDeviceEnrolled(const std::string& additional_token) { @@ -323,6 +366,7 @@ } void EnrollmentScreen::ShowEnrollmentStatusOnSuccess() { + retry_backoff_->InformOfRequest(true); if (elapsed_timer_) UMA_ENROLLMENT_TIME(kMetricEnrollmentTimeSuccess, elapsed_timer_); actor_->ShowEnrollmentStatus(
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_screen.h b/chrome/browser/chromeos/login/enrollment/enrollment_screen.h index 6ccefec9..3beb8a8 100644 --- a/chrome/browser/chromeos/login/enrollment/enrollment_screen.h +++ b/chrome/browser/chromeos/login/enrollment/enrollment_screen.h
@@ -9,6 +9,7 @@ #include <string> #include "base/callback_forward.h" +#include "base/cancelable_callback.h" #include "base/compiler_specific.h" #include "base/gtest_prod_util.h" #include "base/macros.h" @@ -19,6 +20,7 @@ #include "chrome/browser/chromeos/policy/enrollment_config.h" #include "components/policy/core/common/cloud/cloud_policy_constants.h" #include "components/policy/core/common/cloud/enterprise_metrics.h" +#include "net/base/backoff_entry.h" namespace base { class ElapsedTimer; @@ -81,6 +83,7 @@ } private: + friend class EnrollmentScreenUnitTest; FRIEND_TEST_ALL_PREFIXES(EnrollmentScreenTest, TestSuccess); FRIEND_TEST_ALL_PREFIXES(AttestationAuthEnrollmentScreenTest, TestCancel); FRIEND_TEST_ALL_PREFIXES(ForcedAttestationAuthEnrollmentScreenTest, @@ -93,6 +96,9 @@ FRIEND_TEST_ALL_PREFIXES(EnterpriseEnrollmentTest, TestAuthCodeGetsProperlyReceivedFromGaia); FRIEND_TEST_ALL_PREFIXES(HandsOffNetworkScreenTest, RequiresNoInput); + FRIEND_TEST_ALL_PREFIXES(EnrollmentScreenUnitTest, Retries); + FRIEND_TEST_ALL_PREFIXES(EnrollmentScreenUnitTest, DoesNotRetryOnTopOfUser); + FRIEND_TEST_ALL_PREFIXES(EnrollmentScreenUnitTest, DoesNotRetryAfterSuccess); // The authentication mechanisms that this class can use. enum Auth { @@ -144,6 +150,14 @@ // Advance to the next authentication mechanism if possible. bool AdvanceToNextAuth(); + // Similar to OnRetry(), but responds to a timer instead of the user + // pressing the Retry button. + void AutomaticRetry(); + + // Processes a request to retry enrollment. + // Called by OnRetry() and AutomaticRetry(). + void ProcessRetry(); + pairing_chromeos::ControllerPairingController* shark_controller_ = nullptr; EnrollmentScreenActor* actor_; @@ -155,6 +169,10 @@ std::string enrolling_user_domain_; std::string auth_code_; std::unique_ptr<base::ElapsedTimer> elapsed_timer_; + net::BackoffEntry::Policy retry_policy_; + std::unique_ptr<net::BackoffEntry> retry_backoff_; + base::CancelableClosure retry_task_; + int num_retries_ = 0; std::unique_ptr<EnterpriseEnrollmentHelper> enrollment_helper_; base::WeakPtrFactory<EnrollmentScreen> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_screen_unittest.cc b/chrome/browser/chromeos/login/enrollment/enrollment_screen_unittest.cc new file mode 100644 index 0000000..f1116c21 --- /dev/null +++ b/chrome/browser/chromeos/login/enrollment/enrollment_screen_unittest.cc
@@ -0,0 +1,177 @@ +// Copyright (c) 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/chromeos/login/enrollment/enrollment_screen.h" +#include "base/bind.h" +#include "base/command_line.h" +#include "base/message_loop/message_loop.h" +#include "base/test/scoped_mock_time_message_loop_task_runner.h" +#include "base/threading/thread_task_runner_handle.h" +#include "chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper.h" +#include "chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_mock.h" +#include "chrome/browser/chromeos/login/enrollment/mock_enrollment_screen.h" +#include "chrome/browser/chromeos/login/screens/mock_base_screen_delegate.h" +#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h" +#include "chrome/browser/chromeos/policy/enrollment_config.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chromeos/chromeos_switches.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "components/pairing/fake_controller_pairing_controller.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::AnyNumber; +using testing::Invoke; + +namespace chromeos { + +class EnrollmentScreenUnitTest : public testing::Test { + public: + EnrollmentScreenUnitTest() : fake_controller_("") { + enrollment_config_.mode = policy::EnrollmentConfig::MODE_ATTESTATION_FORCED; + enrollment_config_.auth_mechanism = + policy::EnrollmentConfig::AUTH_MECHANISM_ATTESTATION; + } + + // Closure passed to EnterpriseEnrollmentHelper::SetupEnrollmentHelperMock + // which creates the EnterpriseEnrollmentHelperMock object that will + // eventually be tied to the EnrollmentScreen. It also sets up the + // appropriate expectations for testing with the Google Mock framework. + // The template parameter should_enroll indicates whether or not + // the EnterpriseEnrollmentHelper should be mocked to successfully enroll. + template <bool should_enroll> + static EnterpriseEnrollmentHelper* MockEnrollmentHelperCreator( + EnterpriseEnrollmentHelper::EnrollmentStatusConsumer* status_consumer, + const policy::EnrollmentConfig& enrollment_config, + const std::string& enrolling_user_domain) { + EnterpriseEnrollmentHelperMock* mock = + new EnterpriseEnrollmentHelperMock(status_consumer); + if (should_enroll) { + EXPECT_CALL(*mock, EnrollUsingAttestation()) + .Times(AnyNumber()) + .WillRepeatedly(Invoke([mock]() { + static_cast<EnrollmentScreen*>(mock->status_consumer()) + ->ShowEnrollmentStatusOnSuccess(); + })); + } else { + EXPECT_CALL(*mock, EnrollUsingAttestation()) + .Times(AnyNumber()) + .WillRepeatedly(Invoke([mock]() { + mock->status_consumer()->OnEnrollmentError( + policy::EnrollmentStatus::ForStatus( + policy::EnrollmentStatus::REGISTRATION_FAILED)); + })); + } + return mock; + } + + // Creates the EnrollmentScreen and sets required parameters. + void SetUpEnrollmentScreen() { + enrollment_screen_.reset( + new EnrollmentScreen(&mock_delegate_, &mock_actor_)); + enrollment_screen_->SetParameters(enrollment_config_, &fake_controller_); + } + + // Fast forwards time by the specified amount. + void FastForwardTime(base::TimeDelta time) { + runner_.task_runner()->FastForwardBy(time); + } + + // testing::Test: + void SetUp() override { + // Initialize the thread manager. + DBusThreadManager::Initialize(); + + // Configure the browser to use Hands-Off Enrollment. + base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( + switches::kEnterpriseEnableZeroTouchEnrollment, "hands-off"); + } + + void TearDown() override { + TestingBrowserProcess::GetGlobal()->SetShuttingDown(true); + DBusThreadManager::Shutdown(); + } + + protected: + // A pointer to the EnrollmentScreen. + std::unique_ptr<EnrollmentScreen> enrollment_screen_; + + private: + // Replace main thread's task runner with a mock for duration of test. + base::MessageLoop loop_; + base::ScopedMockTimeMessageLoopTaskRunner runner_; + + // Objects required by the EnrollmentScreen that can be re-used. + policy::EnrollmentConfig enrollment_config_; + pairing_chromeos::FakeControllerPairingController fake_controller_; + MockBaseScreenDelegate mock_delegate_; + MockEnrollmentScreenActor mock_actor_; + + DISALLOW_COPY_AND_ASSIGN(EnrollmentScreenUnitTest); +}; + +TEST_F(EnrollmentScreenUnitTest, Retries) { + // Define behavior of EnterpriseEnrollmentHelperMock to always fail + // enrollment. + EnterpriseEnrollmentHelper::SetupEnrollmentHelperMock( + &EnrollmentScreenUnitTest::MockEnrollmentHelperCreator<false>); + + SetUpEnrollmentScreen(); + + // Remove jitter to enable deterministic testing. + enrollment_screen_->retry_policy_.jitter_factor = 0; + + // Start zero-touch enrollment. + enrollment_screen_->Show(); + + // Fast forward time by 1 minute. + FastForwardTime(base::TimeDelta::FromMinutes(1)); + + // Check that we have retried 4 times. + EXPECT_EQ(enrollment_screen_->num_retries_, 4); +} + +TEST_F(EnrollmentScreenUnitTest, DoesNotRetryOnTopOfUser) { + // Define behavior of EnterpriseEnrollmentHelperMock to always fail + // enrollment. + EnterpriseEnrollmentHelper::SetupEnrollmentHelperMock( + &EnrollmentScreenUnitTest::MockEnrollmentHelperCreator<false>); + + SetUpEnrollmentScreen(); + + // Remove jitter to enable deterministic testing. + enrollment_screen_->retry_policy_.jitter_factor = 0; + + // Start zero-touch enrollment. + enrollment_screen_->Show(); + + // Schedule user retry button click after 30 sec. + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, base::Bind(&EnrollmentScreen::OnRetry, + enrollment_screen_->weak_ptr_factory_.GetWeakPtr()), + base::TimeDelta::FromSeconds(30)); + + // Fast forward time by 1 minute. + FastForwardTime(base::TimeDelta::FromMinutes(1)); + + // Check that the number of retries is still 4. + EXPECT_EQ(enrollment_screen_->num_retries_, 4); +} + +TEST_F(EnrollmentScreenUnitTest, DoesNotRetryAfterSuccess) { + // Define behavior of EnterpriseEnrollmentHelperMock to successfully enroll. + EnterpriseEnrollmentHelper::SetupEnrollmentHelperMock( + &EnrollmentScreenUnitTest::MockEnrollmentHelperCreator<true>); + + SetUpEnrollmentScreen(); + + // Start zero-touch enrollment. + enrollment_screen_->Show(); + + // Fast forward time by 1 minute. + FastForwardTime(base::TimeDelta::FromMinutes(1)); + + // Check that we do not retry. + EXPECT_EQ(enrollment_screen_->num_retries_, 0); +} +} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_impl.cc b/chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_impl.cc index a7495932..65c8f8c 100644 --- a/chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_impl.cc +++ b/chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_impl.cc
@@ -357,6 +357,10 @@ break; case policy::DM_STATUS_CANNOT_SIGN_REQUEST: UMA(policy::kMetricEnrollmentRegisterCannotSignRequest); + break; + case policy::DM_STATUS_SERVICE_ARC_DISABLED: + NOTREACHED(); + break; } break; case policy::EnrollmentStatus::REGISTRATION_BAD_MODE:
diff --git a/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc b/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc index 53534af..5d0d29c0 100644 --- a/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc +++ b/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc
@@ -4,23 +4,37 @@ #include "base/command_line.h" #include "base/memory/ref_counted.h" +#include "base/threading/thread_task_runner_handle.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/login/startup_utils.h" #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h" #include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h" #include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/browser/lifetime/application_lifetime.h" +#include "chrome/grit/generated_resources.h" +#include "chrome/test/base/ui_test_utils.h" #include "chromeos/chromeos_switches.h" #include "chromeos/settings/cros_settings_names.h" #include "components/user_manager/user_manager.h" -#include "content/public/test/test_utils.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/ime/chromeos/input_method_manager.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" namespace em = enterprise_management; namespace chromeos { class LoginScreenPolicyTest : public policy::DevicePolicyCrosBrowserTest { + public: + void RefreshDevicePolicyAndWaitForSettingChange( + const char* cros_setting_name); + + protected: void SetUpCommandLine(base::CommandLine* command_line) override { command_line->AppendSwitch(switches::kLoginManager); + command_line->AppendSwitch(switches::kForceLoginManagerInTests); } void SetUpInProcessBrowserTestFixture() override { @@ -28,25 +42,94 @@ MarkAsEnterpriseOwned(); DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture(); } + + void TearDownOnMainThread() override { + // This shuts down the login UI. + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&chrome::AttemptExit)); + base::RunLoop().RunUntilIdle(); + } }; -IN_PROC_BROWSER_TEST_F(LoginScreenPolicyTest, DisableSupervisedUsers) { - EXPECT_FALSE(user_manager::UserManager::Get()->AreSupervisedUsersAllowed()); - +void LoginScreenPolicyTest::RefreshDevicePolicyAndWaitForSettingChange( + const char* cros_setting_name) { scoped_refptr<content::MessageLoopRunner> runner( new content::MessageLoopRunner); std::unique_ptr<CrosSettings::ObserverSubscription> subscription( chromeos::CrosSettings::Get()->AddSettingsObserver( - chromeos::kAccountsPrefSupervisedUsersEnabled, - runner->QuitClosure())); + cros_setting_name, runner->QuitClosure())); + + RefreshDevicePolicy(); + runner->Run(); +} + +IN_PROC_BROWSER_TEST_F(LoginScreenPolicyTest, DisableSupervisedUsers) { + EXPECT_FALSE(user_manager::UserManager::Get()->AreSupervisedUsersAllowed()); em::ChromeDeviceSettingsProto& proto(device_policy()->payload()); proto.mutable_supervised_users_settings()->set_supervised_users_enabled(true); - RefreshDevicePolicy(); - - runner->Run(); + RefreshDevicePolicyAndWaitForSettingChange( + chromeos::kAccountsPrefSupervisedUsersEnabled); EXPECT_TRUE(user_manager::UserManager::Get()->AreSupervisedUsersAllowed()); } +IN_PROC_BROWSER_TEST_F(LoginScreenPolicyTest, RestrictInputMethods) { + input_method::InputMethodManager* imm = + input_method::InputMethodManager::Get(); + ASSERT_TRUE(imm); + + ASSERT_EQ(0U, imm->GetActiveIMEState()->GetAllowedInputMethods().size()); + + em::ChromeDeviceSettingsProto& proto(device_policy()->payload()); + proto.mutable_login_screen_input_methods()->add_login_screen_input_methods( + "xkb:de::ger"); + RefreshDevicePolicyAndWaitForSettingChange( + chromeos::kDeviceLoginScreenInputMethods); + + ASSERT_EQ(1U, imm->GetActiveIMEState()->GetAllowedInputMethods().size()); + + // Remove the policy again + proto.mutable_login_screen_input_methods() + ->clear_login_screen_input_methods(); + RefreshDevicePolicyAndWaitForSettingChange( + chromeos::kDeviceLoginScreenInputMethods); + + ASSERT_EQ(0U, imm->GetActiveIMEState()->GetAllowedInputMethods().size()); +} + +class LoginScreenLocalePolicyTest : public LoginScreenPolicyTest { + protected: + LoginScreenLocalePolicyTest() {} + + void SetUpInProcessBrowserTestFixture() override { + LoginScreenPolicyTest::SetUpInProcessBrowserTestFixture(); + + em::ChromeDeviceSettingsProto& proto(device_policy()->payload()); + proto.mutable_login_screen_locales()->add_login_screen_locales("fr-FR"); + RefreshDevicePolicy(); + } +}; + +IN_PROC_BROWSER_TEST_F(LoginScreenLocalePolicyTest, + PRE_LoginLocaleEnforcedByPolicy) { + chromeos::StartupUtils::MarkOobeCompleted(); +} + +IN_PROC_BROWSER_TEST_F(LoginScreenLocalePolicyTest, + LoginLocaleEnforcedByPolicy) { + // Verifies that the default locale can be overridden with policy. + EXPECT_EQ("fr", g_browser_process->GetApplicationLocale()); + base::string16 french_title = + l10n_util::GetStringUTF16(IDS_LOGIN_POD_SIGNING_IN); + + // Make sure this is really French and differs from the English title. + std::string loaded = + ui::ResourceBundle::GetSharedInstance().ReloadLocaleResources("en-US"); + EXPECT_EQ("en-US", loaded); + base::string16 english_title = + l10n_util::GetStringUTF16(IDS_LOGIN_POD_SIGNING_IN); + EXPECT_NE(french_title, english_title); +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/mock_update_screen.cc b/chrome/browser/chromeos/login/screens/mock_update_screen.cc index 02da115..8b5df54a 100644 --- a/chrome/browser/chromeos/login/screens/mock_update_screen.cc +++ b/chrome/browser/chromeos/login/screens/mock_update_screen.cc
@@ -17,22 +17,22 @@ MockUpdateScreen::~MockUpdateScreen() { } -MockUpdateView::MockUpdateView() : model_(nullptr) { +MockUpdateView::MockUpdateView() { EXPECT_CALL(*this, MockBind(_)).Times(AtLeast(1)); } MockUpdateView::~MockUpdateView() { - if (model_) - model_->OnViewDestroyed(this); + if (screen_) + screen_->OnViewDestroyed(this); } -void MockUpdateView::Bind(UpdateModel& model) { - model_ = &model; - MockBind(model); +void MockUpdateView::Bind(UpdateScreen* screen) { + screen_ = screen; + MockBind(screen); } void MockUpdateView::Unbind() { - model_ = nullptr; + screen_ = nullptr; MockUnbind(); }
diff --git a/chrome/browser/chromeos/login/screens/mock_update_screen.h b/chrome/browser/chromeos/login/screens/mock_update_screen.h index 896eb77e..d69cfe2 100644 --- a/chrome/browser/chromeos/login/screens/mock_update_screen.h +++ b/chrome/browser/chromeos/login/screens/mock_update_screen.h
@@ -6,7 +6,6 @@ #define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_MOCK_UPDATE_SCREEN_H_ #include "chrome/browser/chromeos/login/screens/base_screen_delegate.h" -#include "chrome/browser/chromeos/login/screens/update_model.h" #include "chrome/browser/chromeos/login/screens/update_screen.h" #include "chrome/browser/chromeos/login/screens/update_view.h" #include "testing/gmock/include/gmock/gmock.h" @@ -26,16 +25,16 @@ MockUpdateView(); virtual ~MockUpdateView(); - void Bind(UpdateModel& model) override; + void Bind(UpdateScreen* screen) override; void Unbind() override; MOCK_METHOD0(Show, void()); MOCK_METHOD0(Hide, void()); - MOCK_METHOD1(MockBind, void(UpdateModel& model)); + MOCK_METHOD1(MockBind, void(UpdateScreen* screen)); MOCK_METHOD0(MockUnbind, void()); private: - UpdateModel* model_; + UpdateScreen* screen_ = nullptr; }; } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/update_model.cc b/chrome/browser/chromeos/login/screens/update_model.cc deleted file mode 100644 index d03f775..0000000 --- a/chrome/browser/chromeos/login/screens/update_model.cc +++ /dev/null
@@ -1,27 +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 "chrome/browser/chromeos/login/screens/update_model.h" - -#include "chrome/browser/chromeos/login/wizard_controller.h" - -namespace chromeos { - -const char UpdateModel::kUserActionCancelUpdateShortcut[] = "cancel-update"; -const char UpdateModel::kContextKeyEstimatedTimeLeftSec[] = "time-left-sec"; -const char UpdateModel::kContextKeyShowEstimatedTimeLeft[] = "show-time-left"; -const char UpdateModel::kContextKeyUpdateMessage[] = "update-msg"; -const char UpdateModel::kContextKeyShowCurtain[] = "show-curtain"; -const char UpdateModel::kContextKeyShowProgressMessage[] = "show-progress-msg"; -const char UpdateModel::kContextKeyProgress[] = "progress"; -const char UpdateModel::kContextKeyProgressMessage[] = "progress-msg"; -const char UpdateModel::kContextKeyCancelUpdateShortcutEnabled[] = - "cancel-update-enabled"; - -UpdateModel::UpdateModel(BaseScreenDelegate* base_screen_delegate) - : BaseScreen(base_screen_delegate, OobeScreen::SCREEN_OOBE_UPDATE) {} - -UpdateModel::~UpdateModel() {} - -} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/update_model.h b/chrome/browser/chromeos/login/screens/update_model.h deleted file mode 100644 index 2a8a7ed2..0000000 --- a/chrome/browser/chromeos/login/screens/update_model.h +++ /dev/null
@@ -1,37 +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 CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_UPDATE_MODEL_H_ -#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_UPDATE_MODEL_H_ - -#include "chrome/browser/chromeos/login/screens/base_screen.h" - -namespace chromeos { - -class BaseScreenDelegate; -class UpdateView; - -class UpdateModel : public BaseScreen { - public: - static const char kUserActionCancelUpdateShortcut[]; - static const char kContextKeyEstimatedTimeLeftSec[]; - static const char kContextKeyShowEstimatedTimeLeft[]; - static const char kContextKeyUpdateMessage[]; - static const char kContextKeyShowCurtain[]; - static const char kContextKeyShowProgressMessage[]; - static const char kContextKeyProgress[]; - static const char kContextKeyProgressMessage[]; - static const char kContextKeyCancelUpdateShortcutEnabled[]; - - explicit UpdateModel(BaseScreenDelegate* base_screen_delegate); - ~UpdateModel() override; - - // This method is called, when view is being destroyed. Note, if model - // is destroyed earlier then it has to call Unbind(). - virtual void OnViewDestroyed(UpdateView* view) = 0; -}; - -} // namespace chromeos - -#endif // CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_UPDATE_MODEL_H_
diff --git a/chrome/browser/chromeos/login/screens/update_screen.cc b/chrome/browser/chromeos/login/screens/update_screen.cc index 864b44c..f179953 100644 --- a/chrome/browser/chromeos/login/screens/update_screen.cc +++ b/chrome/browser/chromeos/login/screens/update_screen.cc
@@ -35,6 +35,20 @@ namespace { +constexpr const char kContextKeyEstimatedTimeLeftSec[] = "time-left-sec"; +constexpr const char kContextKeyShowEstimatedTimeLeft[] = "show-time-left"; +constexpr const char kContextKeyUpdateMessage[] = "update-msg"; +constexpr const char kContextKeyShowCurtain[] = "show-curtain"; +constexpr const char kContextKeyShowProgressMessage[] = "show-progress-msg"; +constexpr const char kContextKeyProgress[] = "progress"; +constexpr const char kContextKeyProgressMessage[] = "progress-msg"; + +#if !defined(OFFICIAL_BUILD) +constexpr const char kUserActionCancelUpdateShortcut[] = "cancel-update"; +constexpr const char kContextKeyCancelUpdateShortcutEnabled[] = + "cancel-update-enabled"; +#endif + // If reboot didn't happen, ask user to reboot device manually. const int kWaitForRebootTimeSec = 3; @@ -110,22 +124,14 @@ UpdateScreen::UpdateScreen(BaseScreenDelegate* base_screen_delegate, UpdateView* view, HostPairingController* remora_controller) - : UpdateModel(base_screen_delegate), - state_(STATE_IDLE), + : BaseScreen(base_screen_delegate, OobeScreen::SCREEN_OOBE_UPDATE), reboot_check_delay_(kWaitForRebootTimeSec), - is_checking_for_update_(true), - is_downloading_update_(false), - is_ignore_update_deadlines_(false), - is_shown_(false), - ignore_idle_status_(true), view_(view), remora_controller_(remora_controller), - is_first_detection_notification_(true), - is_first_portal_notification_(true), histogram_helper_(new ErrorScreensHistogramHelper("Update")), weak_factory_(this) { if (view_) - view_->Bind(*this); + view_->Bind(this); GetInstanceSet().insert(this); } @@ -139,6 +145,78 @@ GetInstanceSet().erase(this); } +void UpdateScreen::OnViewDestroyed(UpdateView* view) { + if (view_ == view) + view_ = nullptr; +} + +void UpdateScreen::StartNetworkCheck() { + // If portal detector is enabled and portal detection before AU is + // allowed, initiate network state check. Otherwise, directly + // proceed to update. + if (!network_portal_detector::GetInstance()->IsEnabled()) { + StartUpdateCheck(); + return; + } + state_ = State::STATE_FIRST_PORTAL_CHECK; + is_first_detection_notification_ = true; + is_first_portal_notification_ = true; + network_portal_detector::GetInstance()->AddAndFireObserver(this); +} + +void UpdateScreen::SetIgnoreIdleStatus(bool ignore_idle_status) { + ignore_idle_status_ = ignore_idle_status; +} + +void UpdateScreen::ExitUpdate(UpdateScreen::ExitReason reason) { + DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this); + network_portal_detector::GetInstance()->RemoveObserver(this); + SetHostPairingControllerStatus(HostPairingController::UPDATE_STATUS_UPDATED); + + switch (reason) { + case REASON_UPDATE_CANCELED: + Finish(BaseScreenDelegate::UPDATE_NOUPDATE); + break; + case REASON_UPDATE_INIT_FAILED: + Finish(BaseScreenDelegate::UPDATE_ERROR_CHECKING_FOR_UPDATE); + break; + case REASON_UPDATE_NON_CRITICAL: + case REASON_UPDATE_ENDED: { + UpdateEngineClient* update_engine_client = + DBusThreadManager::Get()->GetUpdateEngineClient(); + switch (update_engine_client->GetLastStatus().status) { + case UpdateEngineClient::UPDATE_STATUS_ATTEMPTING_ROLLBACK: + break; + case UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE: + case UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT: + case UpdateEngineClient::UPDATE_STATUS_DOWNLOADING: + case UpdateEngineClient::UPDATE_STATUS_FINALIZING: + case UpdateEngineClient::UPDATE_STATUS_VERIFYING: + DCHECK(!HasCriticalUpdate()); + // Noncritical update, just exit screen as if there is no update. + // no break + case UpdateEngineClient::UPDATE_STATUS_IDLE: + Finish(BaseScreenDelegate::UPDATE_NOUPDATE); + break; + case UpdateEngineClient::UPDATE_STATUS_ERROR: + case UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT: + if (is_checking_for_update_) { + Finish(BaseScreenDelegate::UPDATE_ERROR_CHECKING_FOR_UPDATE); + } else if (HasCriticalUpdate()) { + Finish(BaseScreenDelegate::UPDATE_ERROR_UPDATING_CRITICAL_UPDATE); + } else { + Finish(BaseScreenDelegate::UPDATE_ERROR_UPDATING); + } + break; + default: + NOTREACHED(); + } + } break; + default: + NOTREACHED(); + } +} + void UpdateScreen::UpdateStatusChanged( const UpdateEngineClient::Status& status) { if (is_checking_for_update_ && @@ -284,14 +362,14 @@ is_first_detection_notification_ = false; NetworkPortalDetector::CaptivePortalStatus status = state.status; - if (state_ == STATE_ERROR) { + if (state_ == State::STATE_ERROR) { // In the case of online state hide error message and proceed to // the update stage. Otherwise, update error message content. if (status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE) StartUpdateCheck(); else UpdateErrorMessage(network, status); - } else if (state_ == STATE_FIRST_PORTAL_CHECK) { + } else if (state_ == State::STATE_FIRST_PORTAL_CHECK) { // In the case of online state immediately proceed to the update // stage. Otherwise, prepare and show error message. if (status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE) { @@ -307,18 +385,14 @@ } } -void UpdateScreen::StartNetworkCheck() { - // If portal detector is enabled and portal detection before AU is - // allowed, initiate network state check. Otherwise, directly - // proceed to update. - if (!network_portal_detector::GetInstance()->IsEnabled()) { - StartUpdateCheck(); - return; - } - state_ = STATE_FIRST_PORTAL_CHECK; - is_first_detection_notification_ = true; - is_first_portal_notification_ = true; - network_portal_detector::GetInstance()->AddAndFireObserver(this); +void UpdateScreen::CancelUpdate() { + VLOG(1) << "Forced update cancel"; + ExitUpdate(REASON_UPDATE_CANCELED); +} + +// TODO(jdufault): This should return a pointer. See crbug.com/672142. +base::OneShotTimer& UpdateScreen::GetErrorMessageTimerForTesting() { + return error_message_timer_; } void UpdateScreen::Show() { @@ -341,11 +415,6 @@ is_shown_ = false; } -void UpdateScreen::OnViewDestroyed(UpdateView* view) { - if (view_ == view) - view_ = nullptr; -} - void UpdateScreen::OnUserAction(const std::string& action_id) { #if !defined(OFFICIAL_BUILD) if (action_id == kUserActionCancelUpdateShortcut) @@ -355,84 +424,6 @@ BaseScreen::OnUserAction(action_id); } -void UpdateScreen::OnContextKeyUpdated( - const ::login::ScreenContext::KeyType& key) { - UpdateModel::OnContextKeyUpdated(key); -} - -void UpdateScreen::ExitUpdate(UpdateScreen::ExitReason reason) { - DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this); - network_portal_detector::GetInstance()->RemoveObserver(this); - SetHostPairingControllerStatus(HostPairingController::UPDATE_STATUS_UPDATED); - - - switch (reason) { - case REASON_UPDATE_CANCELED: - Finish(BaseScreenDelegate::UPDATE_NOUPDATE); - break; - case REASON_UPDATE_INIT_FAILED: - Finish(BaseScreenDelegate::UPDATE_ERROR_CHECKING_FOR_UPDATE); - break; - case REASON_UPDATE_NON_CRITICAL: - case REASON_UPDATE_ENDED: - { - UpdateEngineClient* update_engine_client = - DBusThreadManager::Get()->GetUpdateEngineClient(); - switch (update_engine_client->GetLastStatus().status) { - case UpdateEngineClient::UPDATE_STATUS_ATTEMPTING_ROLLBACK: - break; - case UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE: - case UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT: - case UpdateEngineClient::UPDATE_STATUS_DOWNLOADING: - case UpdateEngineClient::UPDATE_STATUS_FINALIZING: - case UpdateEngineClient::UPDATE_STATUS_VERIFYING: - DCHECK(!HasCriticalUpdate()); - // Noncritical update, just exit screen as if there is no update. - // no break - case UpdateEngineClient::UPDATE_STATUS_IDLE: - Finish(BaseScreenDelegate::UPDATE_NOUPDATE); - break; - case UpdateEngineClient::UPDATE_STATUS_ERROR: - case UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT: - if (is_checking_for_update_) { - Finish(BaseScreenDelegate::UPDATE_ERROR_CHECKING_FOR_UPDATE); - } else if (HasCriticalUpdate()) { - Finish(BaseScreenDelegate::UPDATE_ERROR_UPDATING_CRITICAL_UPDATE); - } else { - Finish(BaseScreenDelegate::UPDATE_ERROR_UPDATING); - } - break; - default: - NOTREACHED(); - } - } - break; - default: - NOTREACHED(); - } -} - -void UpdateScreen::OnWaitForRebootTimeElapsed() { - LOG(ERROR) << "Unable to reboot - asking user for a manual reboot."; - MakeSureScreenIsShown(); - GetContextEditor().SetString(kContextKeyUpdateMessage, - l10n_util::GetStringUTF16(IDS_UPDATE_COMPLETED)); -} - -void UpdateScreen::MakeSureScreenIsShown() { - if (!is_shown_) - get_base_screen_delegate()->ShowCurrentScreen(); -} - -void UpdateScreen::SetIgnoreIdleStatus(bool ignore_idle_status) { - ignore_idle_status_ = ignore_idle_status; -} - -void UpdateScreen::CancelUpdate() { - VLOG(1) << "Forced update cancel"; - ExitUpdate(REASON_UPDATE_CANCELED); -} - void UpdateScreen::UpdateDownloadingStats( const UpdateEngineClient::Status& status) { base::Time download_current_time = base::Time::Now(); @@ -503,6 +494,25 @@ return true; } +void UpdateScreen::OnWaitForRebootTimeElapsed() { + LOG(ERROR) << "Unable to reboot - asking user for a manual reboot."; + MakeSureScreenIsShown(); + GetContextEditor().SetString(kContextKeyUpdateMessage, + l10n_util::GetStringUTF16(IDS_UPDATE_COMPLETED)); +} + +void UpdateScreen::MakeSureScreenIsShown() { + if (!is_shown_) + get_base_screen_delegate()->ShowCurrentScreen(); +} + +void UpdateScreen::SetHostPairingControllerStatus( + HostPairingController::UpdateStatus update_status) { + if (remora_controller_) { + remora_controller_->OnUpdateStatusChanged(update_status); + } +} + ErrorScreen* UpdateScreen::GetErrorScreen() { return get_base_screen_delegate()->GetErrorScreen(); } @@ -513,9 +523,9 @@ network_portal_detector::GetInstance()->RemoveObserver(this); connect_request_subscription_.reset(); - if (state_ == STATE_ERROR) + if (state_ == State::STATE_ERROR) HideErrorMessage(); - state_ = STATE_UPDATE; + state_ = State::STATE_UPDATE; DBusThreadManager::Get()->GetUpdateEngineClient()->AddObserver(this); VLOG(1) << "Initiate update check"; DBusThreadManager::Get()->GetUpdateEngineClient()->RequestUpdateCheck( @@ -527,7 +537,7 @@ error_message_timer_.Stop(); - state_ = STATE_ERROR; + state_ = State::STATE_ERROR; connect_request_subscription_ = GetErrorScreen()->RegisterConnectRequestCallback(base::Bind( &UpdateScreen::OnConnectRequested, base::Unretained(this))); @@ -573,29 +583,18 @@ } } -void UpdateScreen::SetHostPairingControllerStatus( - HostPairingController::UpdateStatus update_status) { - if (remora_controller_) { - remora_controller_->OnUpdateStatusChanged(update_status); - } -} - void UpdateScreen::DelayErrorMessage() { if (error_message_timer_.IsRunning()) return; - state_ = STATE_ERROR; + state_ = State::STATE_ERROR; error_message_timer_.Start( FROM_HERE, base::TimeDelta::FromSeconds(kDelayErrorMessageSec), this, &UpdateScreen::ShowErrorMessage); } -base::OneShotTimer& UpdateScreen::GetErrorMessageTimerForTesting() { - return error_message_timer_; -} - void UpdateScreen::OnConnectRequested() { - if (state_ == STATE_ERROR) { + if (state_ == State::STATE_ERROR) { LOG(WARNING) << "Hiding error message since AP was reselected"; StartUpdateCheck(); }
diff --git a/chrome/browser/chromeos/login/screens/update_screen.h b/chrome/browser/chromeos/login/screens/update_screen.h index a3fd36c3..2c60ba4e 100644 --- a/chrome/browser/chromeos/login/screens/update_screen.h +++ b/chrome/browser/chromeos/login/screens/update_screen.h
@@ -14,8 +14,8 @@ #include "base/memory/weak_ptr.h" #include "base/time/time.h" #include "base/timer/timer.h" +#include "chrome/browser/chromeos/login/screens/base_screen.h" #include "chrome/browser/chromeos/login/screens/error_screen.h" -#include "chrome/browser/chromeos/login/screens/update_model.h" #include "chromeos/dbus/update_engine_client.h" #include "chromeos/network/portal_detector/network_portal_detector.h" #include "components/pairing/host_pairing_controller.h" @@ -30,30 +30,27 @@ class UpdateView; // Controller for the update screen. -class UpdateScreen : public UpdateModel, +class UpdateScreen : public BaseScreen, public UpdateEngineClient::Observer, public NetworkPortalDetector::Observer { public: + static UpdateScreen* Get(ScreenManager* manager); + + // Returns true if this instance is still active (i.e. has not been deleted). + static bool HasInstance(UpdateScreen* inst); + UpdateScreen(BaseScreenDelegate* base_screen_delegate, UpdateView* view, pairing_chromeos::HostPairingController* remora_controller); ~UpdateScreen() override; - static UpdateScreen* Get(ScreenManager* manager); - - // UpdateModel: - void Show() override; - void Hide() override; - void OnViewDestroyed(UpdateView* view) override; - void OnUserAction(const std::string& action_id) override; - void OnContextKeyUpdated(const ::login::ScreenContext::KeyType& key) override; + // Called when the being destroyed. This should call Unbind() on the + // associated View if this class is destroyed before it. + void OnViewDestroyed(UpdateView* view); // Starts network check. Made virtual to simplify mocking. virtual void StartNetworkCheck(); - // Returns true if this instance is still active (i.e. has not been deleted). - static bool HasInstance(UpdateScreen* inst); - void SetIgnoreIdleStatus(bool ignore_idle_status); enum ExitReason { @@ -83,13 +80,18 @@ FRIEND_TEST_ALL_PREFIXES(UpdateScreenTest, TestUpdateAvailable); FRIEND_TEST_ALL_PREFIXES(UpdateScreenTest, TestAPReselection); - enum State { + enum class State { STATE_IDLE = 0, STATE_FIRST_PORTAL_CHECK, STATE_UPDATE, STATE_ERROR }; + // BaseScreen: + void Show() override; + void Hide() override; + void OnUserAction(const std::string& action_id) override; + // Updates downloading stats (remaining time and downloading // progress) on the AU screen. void UpdateDownloadingStats(const UpdateEngineClient::Status& status); @@ -128,52 +130,54 @@ base::OneShotTimer reboot_timer_; // Returns a static InstanceSet. + // TODO(jdufault): There should only ever be one instance of this class. + // Remove support for supporting multiple instances. See crbug.com/672142. typedef std::set<UpdateScreen*> InstanceSet; static InstanceSet& GetInstanceSet(); // Current state of the update screen. - State state_; + State state_ = State::STATE_IDLE; // Time in seconds after which we decide that the device has not rebooted // automatically. If reboot didn't happen during this interval, ask user to // reboot device manually. - int reboot_check_delay_; + int reboot_check_delay_ = 0; // True if in the process of checking for update. - bool is_checking_for_update_; + bool is_checking_for_update_ = true; // Flag that is used to detect when update download has just started. - bool is_downloading_update_; + bool is_downloading_update_ = false; // If true, update deadlines are ignored. // Note, this is false by default. - bool is_ignore_update_deadlines_; + bool is_ignore_update_deadlines_ = false; // Whether the update screen is shown. - bool is_shown_; + bool is_shown_ = false; // Ignore fist IDLE status that is sent before update screen initiated check. - bool ignore_idle_status_; + bool ignore_idle_status_ = true; - UpdateView* view_; + UpdateView* view_ = nullptr; // Used to track updates over Bluetooth. pairing_chromeos::HostPairingController* remora_controller_; // Time of the first notification from the downloading stage. base::Time download_start_time_; - double download_start_progress_; + double download_start_progress_ = 0; // Time of the last notification from the downloading stage. base::Time download_last_time_; - double download_last_progress_; + double download_last_progress_ = 0; - bool is_download_average_speed_computed_; - double download_average_speed_; + bool is_download_average_speed_computed_ = false; + double download_average_speed_ = 0; // True if there was no notification from NetworkPortalDetector // about state for the default network. - bool is_first_detection_notification_; + bool is_first_detection_notification_ = true; // True if there was no notification about captive portal state for // the default network. - bool is_first_portal_notification_; + bool is_first_portal_notification_ = true; std::unique_ptr<ErrorScreensHistogramHelper> histogram_helper_;
diff --git a/chrome/browser/chromeos/login/screens/update_view.h b/chrome/browser/chromeos/login/screens/update_view.h index 58c3391..17de164 100644 --- a/chrome/browser/chromeos/login/screens/update_view.h +++ b/chrome/browser/chromeos/login/screens/update_view.h
@@ -9,7 +9,7 @@ namespace chromeos { -class UpdateModel; +class UpdateScreen; // Interface for dependency injection between NetworkScreen and its actual // representation. Owned by UpdateScreen. @@ -23,10 +23,10 @@ // Hides the contents of the screen. virtual void Hide() = 0; - // Binds |model| to the view. - virtual void Bind(UpdateModel& model) = 0; + // Binds |screen| to the view. + virtual void Bind(UpdateScreen* screen) = 0; - // Unbinds model from the view. + // Unbinds the screen from the view. virtual void Unbind() = 0; };
diff --git a/chrome/browser/chromeos/login/screens/user_selection_screen.cc b/chrome/browser/chromeos/login/screens/user_selection_screen.cc index 4b306ea..cb074247 100644 --- a/chrome/browser/chromeos/login/screens/user_selection_screen.cc +++ b/chrome/browser/chromeos/login/screens/user_selection_screen.cc
@@ -133,12 +133,9 @@ } // namespace UserSelectionScreen::UserSelectionScreen(const std::string& display_type) - : handler_(nullptr), - login_display_delegate_(nullptr), - view_(nullptr), + : BaseScreen(nullptr, OobeScreen::SCREEN_USER_SELECTION), display_type_(display_type), - weak_factory_(this) { -} + weak_factory_(this) {} UserSelectionScreen::~UserSelectionScreen() { proximity_auth::ScreenlockBridge::Get()->SetLockHandler(nullptr); @@ -533,6 +530,10 @@ login_display_delegate_->Login(user_context, SigninSpecifics()); } +void UserSelectionScreen::Show() {} + +void UserSelectionScreen::Hide() {} + void UserSelectionScreen::HardLockPod(const AccountId& account_id) { view_->SetAuthType(account_id, OFFLINE_PASSWORD, base::string16()); EasyUnlockService* service = GetEasyUnlockServiceForUser(account_id);
diff --git a/chrome/browser/chromeos/login/screens/user_selection_screen.h b/chrome/browser/chromeos/login/screens/user_selection_screen.h index e6a5b80..26eb81c9 100644 --- a/chrome/browser/chromeos/login/screens/user_selection_screen.h +++ b/chrome/browser/chromeos/login/screens/user_selection_screen.h
@@ -13,9 +13,9 @@ #include "base/macros.h" #include "base/timer/timer.h" #include "base/values.h" +#include "chrome/browser/chromeos/login/screens/base_screen.h" #include "chrome/browser/chromeos/login/signin/token_handle_util.h" #include "chrome/browser/chromeos/login/ui/login_display.h" -#include "chrome/browser/chromeos/login/ui/models/user_board_model.h" #include "components/proximity_auth/screenlock_bridge.h" #include "components/signin/core/account_id/account_id.h" #include "components/user_manager/user.h" @@ -33,7 +33,7 @@ class UserSelectionScreen : public ui::UserActivityObserver, public proximity_auth::ScreenlockBridge::LockHandler, - public UserBoardModel { + public BaseScreen { public: explicit UserSelectionScreen(const std::string& display_type); ~UserSelectionScreen() override; @@ -57,6 +57,14 @@ void HandleGetUsers(); void CheckUserStatus(const AccountId& account_id); + // Build list of users and send it to the webui. + virtual void SendUserList(); + + // Methods for easy unlock support. + void HardLockPod(const AccountId& account_id); + void AttemptEasyUnlock(const AccountId& account_id); + void RecordClickOnLockIcon(const AccountId& account_id); + // ui::UserActivityDetector implementation: void OnUserActivity(const ui::Event* event) override; @@ -82,11 +90,9 @@ const std::string& secret, const std::string& key_label) override; - // UserBoardModel implementation. - void SendUserList() override; - void HardLockPod(const AccountId& account_id) override; - void AttemptEasyUnlock(const AccountId& account_id) override; - void RecordClickOnLockIcon(const AccountId& account_id) override; + // BaseScreen implementation: + void Show() override; + void Hide() override; // Fills |user_dict| with information about |user|. static void FillUserDictionary( @@ -110,14 +116,11 @@ static bool ShouldForceOnlineSignIn(const user_manager::User* user); protected: - LoginDisplayWebUIHandler* handler_; - LoginDisplay::Delegate* login_display_delegate_; - UserBoardView* view_; + UserBoardView* view_ = nullptr; // Map from public session account IDs to recommended locales set by policy. - typedef std::map<AccountId, std::vector<std::string> > - PublicSessionRecommendedLocaleMap; - PublicSessionRecommendedLocaleMap public_session_recommended_locales_; + std::map<AccountId, std::vector<std::string>> + public_session_recommended_locales_; private: EasyUnlockService* GetEasyUnlockServiceForUser( @@ -126,8 +129,11 @@ void OnUserStatusChecked(const AccountId& account_id, TokenHandleUtil::TokenHandleStatus status); + LoginDisplayWebUIHandler* handler_ = nullptr; + LoginDisplay::Delegate* login_display_delegate_ = nullptr; + // Whether to show guest login. - bool show_guest_; + bool show_guest_ = false; // Purpose of the screen (see constants in OobeUI). const std::string display_type_;
diff --git a/chrome/browser/chromeos/login/signin_screen_controller.cc b/chrome/browser/chromeos/login/signin_screen_controller.cc index 71475fd4..e877048 100644 --- a/chrome/browser/chromeos/login/signin_screen_controller.cc +++ b/chrome/browser/chromeos/login/signin_screen_controller.cc
@@ -34,7 +34,7 @@ // Model/View which are then each responsible for automatically unbinding the // other associated View/Model instance. Then we can eliminate this exposed // WeakPtr logic. See crbug.com/685287. - user_board_view_->Bind(*user_selection_screen_); + user_board_view_->Bind(user_selection_screen_.get()); registrar_.Add(this, chrome::NOTIFICATION_SESSION_STARTED, content::NotificationService::AllSources());
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc index 1c9ecf8..493781e 100644 --- a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc +++ b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
@@ -94,6 +94,7 @@ #include "ui/aura/window.h" #include "ui/base/ime/chromeos/extension_ime_util.h" #include "ui/base/ime/chromeos/input_method_manager.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/compositor/layer.h" #include "ui/compositor/layer_animation_observer.h" @@ -173,8 +174,15 @@ DISALLOW_COPY_AND_ASSIGN(AnimationObserver); }; +bool ShouldShowSigninScreen(chromeos::OobeScreen first_screen) { + return (first_screen == chromeos::OobeScreen::SCREEN_UNKNOWN && + chromeos::StartupUtils::IsOobeCompleted()) || + first_screen == chromeos::OobeScreen::SCREEN_SPECIAL_LOGIN; +} + // ShowLoginWizard is split into two parts. This function is sometimes called -// from ShowLoginWizard(), and sometimes from OnLanguageSwitchedCallback() +// from TriggerShowLoginWizardFinish() directly, and sometimes from +// OnLanguageSwitchedCallback() // (if locale was updated). void ShowLoginWizardFinish( chromeos::OobeScreen first_screen, @@ -182,16 +190,20 @@ chromeos::LoginDisplayHost* display_host) { TRACE_EVENT0("chromeos", "ShowLoginWizard::ShowLoginWizardFinish"); - display_host->StartWizard(first_screen); + if (ShouldShowSigninScreen(first_screen)) { + display_host->StartSignInScreen(chromeos::LoginScreenContext()); + } else { + display_host->StartWizard(first_screen); - // Set initial timezone if specified by customization. - const std::string timezone_name = startup_manifest->initial_timezone(); - VLOG(1) << "Initial time zone: " << timezone_name; - // Apply locale customizations only once to preserve whatever locale - // user has changed to during OOBE. - if (!timezone_name.empty()) { - chromeos::system::TimezoneSettings::GetInstance()->SetTimezoneFromID( - base::UTF8ToUTF16(timezone_name)); + // Set initial timezone if specified by customization. + const std::string timezone_name = startup_manifest->initial_timezone(); + VLOG(1) << "Initial time zone: " << timezone_name; + // Apply locale customizations only once to preserve whatever locale + // user has changed to during OOBE. + if (!timezone_name.empty()) { + chromeos::system::TimezoneSettings::GetInstance()->SetTimezoneFromID( + base::UTF8ToUTF16(timezone_name)); + } } } @@ -223,6 +235,46 @@ self->display_host); } +// Triggers ShowLoginWizardFinish directly if no locale switch is required +// (|switch_locale| is empty) or after a locale switch otherwise. +void TriggerShowLoginWizardFinish( + std::string switch_locale, + std::unique_ptr<ShowLoginWizardSwitchLanguageCallbackData> data) { + if (switch_locale.empty()) { + ShowLoginWizardFinish(data->first_screen, data->startup_manifest, + data->display_host); + } else { + chromeos::locale_util::SwitchLanguageCallback callback( + base::Bind(&OnLanguageSwitchedCallback, base::Passed(std::move(data)))); + + // Load locale keyboards here. Hardware layout would be automatically + // enabled. + chromeos::locale_util::SwitchLanguage( + switch_locale, true, true /* login_layouts_only */, callback, + ProfileManager::GetActiveUserProfile()); + } +} + +// Returns the login screen locale mandated by device policy, or an empty string +// if no policy-specified locale is set. +std::string GetManagedLoginScreenLocale() { + chromeos::CrosSettings* cros_settings = chromeos::CrosSettings::Get(); + const base::ListValue* login_screen_locales = nullptr; + if (!cros_settings->GetList(chromeos::kDeviceLoginScreenLocales, + &login_screen_locales)) + return std::string(); + + // Currently, only the first element is used. The setting is a list for future + // compatibility, if dynamically switching locales on the login screen will be + // implemented. + std::string login_screen_locale; + if (login_screen_locales->empty() || + !login_screen_locales->GetString(0, &login_screen_locale)) + return std::string(); + + return login_screen_locale; +} + void EnableSystemSoundsForAccessibility() { chromeos::AccessibilityManager::Get()->EnableSystemSounds(true); } @@ -877,10 +929,15 @@ // the lifetime of host. // Make sure that subsequent calls are not postponed. waiting_for_wallpaper_load_ = false; - if (initialize_webui_hidden_) - ShowWebUI(); - else + if (initialize_webui_hidden_) { + // If we're in the process of switching locale, the wallpaper might + // have finished loading before the locale switch was completed. + // Only show the UI if it already exists. + if (login_window_ && login_view_) + ShowWebUI(); + } else { StartPostponedWebUI(); + } } registrar_.Remove(this, chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED, @@ -1333,12 +1390,20 @@ ->UpdateTimezoneResolver(); } - bool show_login_screen = (first_screen == OobeScreen::SCREEN_UNKNOWN && - StartupUtils::IsOobeCompleted()) || - first_screen == OobeScreen::SCREEN_SPECIAL_LOGIN; + PrefService* prefs = g_browser_process->local_state(); + const std::string& current_locale = + prefs->GetString(prefs::kApplicationLocale); + VLOG(1) << "Current locale: " << current_locale; - if (show_login_screen) { - display_host->StartSignInScreen(LoginScreenContext()); + if (ShouldShowSigninScreen(first_screen)) { + std::string switch_locale = GetManagedLoginScreenLocale(); + if (switch_locale == current_locale) + switch_locale.clear(); + + std::unique_ptr<ShowLoginWizardSwitchLanguageCallbackData> data = + base::MakeUnique<ShowLoginWizardSwitchLanguageCallbackData>( + first_screen, nullptr, display_host); + TriggerShowLoginWizardFinish(switch_locale, std::move(data)); return; } @@ -1350,10 +1415,6 @@ // and has not been set yet. We cannot call // LanguageSwitchMenu::SwitchLanguage here before // EmitLoginPromptReady. - PrefService* prefs = g_browser_process->local_state(); - const std::string& current_locale = - prefs->GetString(prefs::kApplicationLocale); - VLOG(1) << "Current locale: " << current_locale; const std::string& locale = startup_manifest->initial_locale_default(); const std::string& layout = startup_manifest->keyboard_layout(); @@ -1364,8 +1425,12 @@ manager->GetActiveIMEState()->SetInputMethodLoginDefaultFromVPD(locale, layout); + std::unique_ptr<ShowLoginWizardSwitchLanguageCallbackData> data( + new ShowLoginWizardSwitchLanguageCallbackData( + first_screen, startup_manifest, display_host)); + if (!current_locale.empty() || locale.empty()) { - ShowLoginWizardFinish(first_screen, startup_manifest, display_host); + TriggerShowLoginWizardFinish(std::string(), std::move(data)); return; } @@ -1376,16 +1441,7 @@ prefs->SetString(prefs::kApplicationLocale, locale); StartupUtils::SetInitialLocale(locale); - std::unique_ptr<ShowLoginWizardSwitchLanguageCallbackData> data( - new ShowLoginWizardSwitchLanguageCallbackData( - first_screen, startup_manifest, display_host)); - - locale_util::SwitchLanguageCallback callback( - base::Bind(&OnLanguageSwitchedCallback, base::Passed(std::move(data)))); - - // Load locale keyboards here. Hardware layout would be automatically enabled. - locale_util::SwitchLanguage(locale, true, true /* login_layouts_only */, - callback, ProfileManager::GetActiveUserProfile()); + TriggerShowLoginWizardFinish(locale, std::move(data)); } } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/ui/models/user_board_model.cc b/chrome/browser/chromeos/login/ui/models/user_board_model.cc deleted file mode 100644 index 584e3f0..0000000 --- a/chrome/browser/chromeos/login/ui/models/user_board_model.cc +++ /dev/null
@@ -1,14 +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/ui/models/user_board_model.h" - -namespace chromeos { - -UserBoardModel::UserBoardModel() - : BaseScreen(nullptr, OobeScreen::SCREEN_USER_SELECTION) {} - -UserBoardModel::~UserBoardModel() {} - -} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/ui/models/user_board_model.h b/chrome/browser/chromeos/login/ui/models/user_board_model.h deleted file mode 100644 index 11916a7..0000000 --- a/chrome/browser/chromeos/login/ui/models/user_board_model.h +++ /dev/null
@@ -1,34 +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_UI_MODELS_USER_BOARD_MODEL_H_ -#define CHROME_BROWSER_CHROMEOS_LOGIN_UI_MODELS_USER_BOARD_MODEL_H_ - -#include "chrome/browser/chromeos/login/screens/base_screen.h" - -class AccountId; - -namespace chromeos { - -class UserBoardModel : public BaseScreen { - public: - UserBoardModel(); - ~UserBoardModel() override; - - // Build list of users and send it to the webui. - virtual void SendUserList() = 0; - - // Methods for easy unlock support. - virtual void HardLockPod(const AccountId& account_id) = 0; - virtual void AttemptEasyUnlock(const AccountId& account_id) = 0; - virtual void RecordClickOnLockIcon(const AccountId& account_id) = 0; - - // Temorary unused methods: - void Show() override{}; - void Hide() override{}; -}; - -} // namespace chromeos - -#endif // CHROME_BROWSER_CHROMEOS_LOGIN_UI_MODELS_USER_BOARD_MODEL_H_
diff --git a/chrome/browser/chromeos/login/ui/views/user_board_view.h b/chrome/browser/chromeos/login/ui/views/user_board_view.h index 1a4cf33..5577da9 100644 --- a/chrome/browser/chromeos/login/ui/views/user_board_view.h +++ b/chrome/browser/chromeos/login/ui/views/user_board_view.h
@@ -17,7 +17,10 @@ namespace chromeos { -class UserBoardModel; +class UserSelectionScreen; + +// TODO(jdufault): Rename UserBoardView to UserSelectionView. See +// crbug.com/672142. // Interface between user board screen and its representation, either WebUI // or Views one. @@ -25,7 +28,7 @@ public: virtual ~UserBoardView() {} - virtual void Bind(UserBoardModel& model) = 0; + virtual void Bind(UserSelectionScreen* screen) = 0; virtual void Unbind() = 0; virtual base::WeakPtr<UserBoardView> GetWeakPtr() = 0;
diff --git a/chrome/browser/chromeos/note_taking_helper.cc b/chrome/browser/chromeos/note_taking_helper.cc index d39ca6c..d67e272 100644 --- a/chrome/browser/chromeos/note_taking_helper.cc +++ b/chrome/browser/chromeos/note_taking_helper.cc
@@ -151,7 +151,8 @@ bool NoteTakingHelper::IsAppAvailable(Profile* profile) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(profile); - return ash::IsPaletteFeatureEnabled() && !GetAvailableApps(profile).empty(); + return ash::palette_utils::HasStylusInput() && + !GetAvailableApps(profile).empty(); } void NoteTakingHelper::LaunchAppForNewNote(Profile* profile,
diff --git a/chrome/browser/chromeos/note_taking_helper_unittest.cc b/chrome/browser/chromeos/note_taking_helper_unittest.cc index ec9971e..d6d12b1 100644 --- a/chrome/browser/chromeos/note_taking_helper_unittest.cc +++ b/chrome/browser/chromeos/note_taking_helper_unittest.cc
@@ -179,7 +179,7 @@ if (flags & ENABLE_PALETTE) { base::CommandLine::ForCurrentProcess()->AppendSwitch( - ash::switches::kAshEnablePalette); + ash::switches::kAshForceEnablePalette); } // TODO(derat): Sigh, something in ArcAppTest appears to be re-enabling ARC.
diff --git a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc index 301e4aa..7e1dc1e 100644 --- a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc +++ b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
@@ -332,6 +332,56 @@ policies->Set(key::kLoginApps, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, std::move(login_apps), nullptr); } + + if (policy.has_login_screen_power_management()) { + const em::LoginScreenPowerManagementProto& container( + policy.login_screen_power_management()); + if (container.has_login_screen_power_management()) { + std::unique_ptr<base::Value> decoded_json; + decoded_json = DecodeJsonStringAndDropUnknownBySchema( + container.login_screen_power_management(), + key::kDeviceLoginScreenPowerManagement); + if (decoded_json) { + policies->Set(key::kDeviceLoginScreenPowerManagement, + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_CLOUD, std::move(decoded_json), nullptr); + } + } + } + + if (policy.has_login_screen_domain_auto_complete()) { + const em::LoginScreenDomainAutoCompleteProto& container( + policy.login_screen_domain_auto_complete()); + policies->Set(key::kDeviceLoginScreenDomainAutoComplete, + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_CLOUD, + base::MakeUnique<base::StringValue>( + container.login_screen_domain_auto_complete()), + nullptr); + } + + if (policy.has_login_screen_locales()) { + std::unique_ptr<base::ListValue> locales(new base::ListValue); + const em::LoginScreenLocalesProto& login_screen_locales( + policy.login_screen_locales()); + for (const auto& locale : login_screen_locales.login_screen_locales()) + locales->AppendString(locale); + policies->Set(key::kDeviceLoginScreenLocales, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, std::move(locales), + nullptr); + } + + if (policy.has_login_screen_input_methods()) { + std::unique_ptr<base::ListValue> input_methods(new base::ListValue); + const em::LoginScreenInputMethodsProto& login_screen_input_methods( + policy.login_screen_input_methods()); + for (const auto& input_method : + login_screen_input_methods.login_screen_input_methods()) + input_methods->AppendString(input_method); + policies->Set(key::kDeviceLoginScreenInputMethods, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, + std::move(input_methods), nullptr); + } } void DecodeNetworkPolicies(const em::ChromeDeviceSettingsProto& policy, @@ -753,22 +803,6 @@ } } - if (policy.has_login_screen_power_management()) { - const em::LoginScreenPowerManagementProto& container( - policy.login_screen_power_management()); - if (container.has_login_screen_power_management()) { - std::unique_ptr<base::Value> decoded_json; - decoded_json = DecodeJsonStringAndDropUnknownBySchema( - container.login_screen_power_management(), - key::kDeviceLoginScreenPowerManagement); - if (decoded_json) { - policies->Set(key::kDeviceLoginScreenPowerManagement, - POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, - POLICY_SOURCE_CLOUD, std::move(decoded_json), nullptr); - } - } - } - if (policy.has_system_settings()) { const em::SystemSettingsProto& container(policy.system_settings()); if (container.has_block_devmode()) { @@ -790,17 +824,6 @@ } } - if (policy.has_login_screen_domain_auto_complete()) { - const em::LoginScreenDomainAutoCompleteProto& container( - policy.login_screen_domain_auto_complete()); - policies->Set(key::kDeviceLoginScreenDomainAutoComplete, - POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, - POLICY_SOURCE_CLOUD, - base::MakeUnique<base::StringValue>( - container.login_screen_domain_auto_complete()), - nullptr); - } - if (policy.has_display_rotation_default()) { const em::DisplayRotationDefaultProto& container( policy.display_rotation_default());
diff --git a/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto b/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto index 50ce9a6..6c5a9b7 100644 --- a/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto +++ b/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto
@@ -754,6 +754,16 @@ repeated string login_apps = 1; } +// A list of allowed locales on the login page. +message LoginScreenLocalesProto { + repeated string login_screen_locales = 1; +} + +// A list of allowed input methods on the login page. +message LoginScreenInputMethodsProto { + repeated string login_screen_input_methods = 1; +} + // The url and hash that specified in JSON format that can be used to set the // device-level wallpaper on the login screen before any user logs in. message DeviceWallpaperImageProto { @@ -815,4 +825,6 @@ optional LoginAppsProto login_apps = 46; optional NetworkThrottlingEnabledProto network_throttling = 47; optional DeviceWallpaperImageProto device_wallpaper_image = 48; + optional LoginScreenLocalesProto login_screen_locales = 49; + optional LoginScreenInputMethodsProto login_screen_input_methods = 50; }
diff --git a/chrome/browser/chromeos/settings/device_settings_provider.cc b/chrome/browser/chromeos/settings/device_settings_provider.cc index 423ab66..e954622d 100644 --- a/chrome/browser/chromeos/settings/device_settings_provider.cc +++ b/chrome/browser/chromeos/settings/device_settings_provider.cc
@@ -98,6 +98,8 @@ kTargetVersionPrefix, kUpdateDisabled, kVariationsRestrictParameter, + kDeviceLoginScreenLocales, + kDeviceLoginScreenInputMethods, }; void DecodeLoginPolicies( @@ -310,6 +312,26 @@ login_apps->AppendString(login_app); new_values_cache->SetValue(kLoginApps, std::move(login_apps)); } + + if (policy.has_login_screen_locales()) { + std::unique_ptr<base::ListValue> locales(new base::ListValue); + const em::LoginScreenLocalesProto& login_screen_locales( + policy.login_screen_locales()); + for (const auto& locale : login_screen_locales.login_screen_locales()) + locales->AppendString(locale); + new_values_cache->SetValue(kDeviceLoginScreenLocales, std::move(locales)); + } + + if (policy.has_login_screen_input_methods()) { + std::unique_ptr<base::ListValue> input_methods(new base::ListValue); + const em::LoginScreenInputMethodsProto& login_screen_input_methods( + policy.login_screen_input_methods()); + for (const auto& input_method : + login_screen_input_methods.login_screen_input_methods()) + input_methods->AppendString(input_method); + new_values_cache->SetValue(kDeviceLoginScreenInputMethods, + std::move(input_methods)); + } } void DecodeNetworkPolicies(
diff --git a/chrome/browser/component_updater/subresource_filter_component_installer.cc b/chrome/browser/component_updater/subresource_filter_component_installer.cc index 861819b..f3de4f0 100644 --- a/chrome/browser/component_updater/subresource_filter_component_installer.cc +++ b/chrome/browser/component_updater/subresource_filter_component_installer.cc
@@ -115,9 +115,30 @@ return kSubresourceFilterSetFetcherManifestName; } +// static +std::string SubresourceFilterComponentInstallerTraits::GetInstallerTag() { + std::string ruleset_flavor = subresource_filter::GetRulesetFlavor(); + if (ruleset_flavor.empty()) + return ruleset_flavor; + + // We allow 4 ruleset flavor identifiers: a, b, c, d + if (ruleset_flavor.size() == 1 && ruleset_flavor.at(0) >= 'a' && + ruleset_flavor.at(0) <= 'd') + return ruleset_flavor; + + // Return 'invalid' for any cases where we encounter an invalid installer + // tag. This allows us to verify that no clients are encountering invalid + // installer tags in the field. + return "invalid"; +} + update_client::InstallerAttributes SubresourceFilterComponentInstallerTraits::GetInstallerAttributes() const { - return update_client::InstallerAttributes(); + update_client::InstallerAttributes attributes; + std::string installer_tag = GetInstallerTag(); + if (!installer_tag.empty()) + attributes["tag"] = installer_tag; + return attributes; } std::vector<std::string>
diff --git a/chrome/browser/component_updater/subresource_filter_component_installer.h b/chrome/browser/component_updater/subresource_filter_component_installer.h index e9d5ade..e50bb79 100644 --- a/chrome/browser/component_updater/subresource_filter_component_installer.h +++ b/chrome/browser/component_updater/subresource_filter_component_installer.h
@@ -31,6 +31,8 @@ private: friend class SubresourceFilterComponentInstallerTest; + static std::string GetInstallerTag(); + // ComponentInstallerTraits implementation. bool SupportsGroupPolicyEnabledComponentUpdates() const override; bool RequiresNetworkEncryption() const override;
diff --git a/chrome/browser/component_updater/subresource_filter_component_installer_unittest.cc b/chrome/browser/component_updater/subresource_filter_component_installer_unittest.cc index 7b345b23..c4640f7c 100644 --- a/chrome/browser/component_updater/subresource_filter_component_installer_unittest.cc +++ b/chrome/browser/component_updater/subresource_filter_component_installer_unittest.cc
@@ -154,6 +154,21 @@ base::RunLoop().RunUntilIdle(); } + update_client::InstallerAttributes GetInstallerAttributes() { + return traits_->GetInstallerAttributes(); + } + + void ExpectInstallerTag(const char* expected_tag, + const char* ruleset_flavor) { + base::FieldTrialList field_trial_list(nullptr /* entropy_provider */); + subresource_filter::testing::ScopedSubresourceFilterFeatureToggle + scoped_feature_toggle(base::FeatureList::OVERRIDE_ENABLE_FEATURE, + {{subresource_filter::kRulesetFlavorParameterName, + ruleset_flavor}}); + EXPECT_EQ(expected_tag, + SubresourceFilterComponentInstallerTraits::GetInstallerTag()); + } + private: content::TestBrowserThreadBundle thread_bundle_; base::ScopedTempDir component_install_dir_; @@ -238,4 +253,47 @@ EXPECT_EQ(expected_license_contents, actual_license_contents); } +TEST_F(SubresourceFilterComponentInstallerTest, InstallerTag) { + ExpectInstallerTag("", ""); + ExpectInstallerTag("a", "a"); + ExpectInstallerTag("b", "b"); + ExpectInstallerTag("c", "c"); + ExpectInstallerTag("d", "d"); + ExpectInstallerTag("invalid", "e"); + ExpectInstallerTag("invalid", "foo"); +} + +TEST_F(SubresourceFilterComponentInstallerTest, InstallerAttributesDefault) { + base::FieldTrialList field_trial_list(nullptr /* entropy_provider */); + subresource_filter::testing::ScopedSubresourceFilterFeatureToggle + scoped_feature_toggle(base::FeatureList::OVERRIDE_ENABLE_FEATURE, + std::map<std::string, std::string>()); + EXPECT_EQ(update_client::InstallerAttributes(), GetInstallerAttributes()); +} + +TEST_F(SubresourceFilterComponentInstallerTest, InstallerAttributesCustomTag) { + constexpr char kTagKey[] = "tag"; + constexpr char kTagValue[] = "a"; + + base::FieldTrialList field_trial_list(nullptr /* entropy_provider */); + subresource_filter::testing::ScopedSubresourceFilterFeatureToggle + scoped_feature_toggle( + base::FeatureList::OVERRIDE_ENABLE_FEATURE, + {{subresource_filter::kRulesetFlavorParameterName, kTagValue}}); + EXPECT_EQ(update_client::InstallerAttributes({{kTagKey, kTagValue}}), + GetInstallerAttributes()); +} + +TEST_F(SubresourceFilterComponentInstallerTest, + InstallerAttributesFeatureDisabled) { + constexpr char kTagValue[] = "test_value"; + + base::FieldTrialList field_trial_list(nullptr /* entropy_provider */); + subresource_filter::testing::ScopedSubresourceFilterFeatureToggle + scoped_feature_toggle( + base::FeatureList::OVERRIDE_USE_DEFAULT, + {{subresource_filter::kRulesetFlavorParameterName, kTagValue}}); + EXPECT_EQ(update_client::InstallerAttributes(), GetInstallerAttributes()); +} + } // namespace component_updater
diff --git a/chrome/browser/devtools/device/devtools_device_discovery.cc b/chrome/browser/devtools/device/devtools_device_discovery.cc index 432f3dd6..184c512 100644 --- a/chrome/browser/devtools/device/devtools_device_discovery.cc +++ b/chrome/browser/devtools/device/devtools_device_discovery.cc
@@ -138,6 +138,7 @@ bool Activate() override; void Reload() override; bool Close() override; + base::TimeTicks GetLastActivityTime() override; void SendMessageToBackend(const std::string& message) override; void OnSocketOpened() override; @@ -316,6 +317,10 @@ return true; } +base::TimeTicks AgentHostDelegate::GetLastActivityTime() { + return base::TimeTicks(); +} + void AgentHostDelegate::SendMessageToBackend(const std::string& message) { // We could have detached due to physical connection being closed. if (!proxy_)
diff --git a/chrome/browser/download/notification/download_item_notification.cc b/chrome/browser/download/notification/download_item_notification.cc index 4ed7ee1b..67c699e 100644 --- a/chrome/browser/download/notification/download_item_notification.cc +++ b/chrome/browser/download/notification/download_item_notification.cc
@@ -9,6 +9,7 @@ #include "base/files/file_util.h" #include "base/strings/utf_string_conversions.h" +#include "base/task_scheduler/post_task.h" #include "build/build_config.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/download/download_crx_util.h" @@ -64,8 +65,6 @@ const int64_t kMaxImagePreviewSize = 10 * 1024 * 1024; // 10 MB std::string ReadNotificationImage(const base::FilePath& file_path) { - DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); - std::string data; bool ret = base::ReadFileToString(file_path, &data); if (!ret) @@ -481,8 +480,9 @@ if (model.HasSupportedImageMimeType()) { base::FilePath file_path = item_->GetFullPath(); - base::PostTaskAndReplyWithResult( - content::BrowserThread::GetBlockingPool(), FROM_HERE, + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, base::TaskTraits().MayBlock().WithPriority( + base::TaskPriority::BACKGROUND), base::Bind(&ReadNotificationImage, file_path), base::Bind(&DownloadItemNotification::OnImageLoaded, weak_factory_.GetWeakPtr())); @@ -599,8 +599,9 @@ return; } - base::PostTaskAndReplyWithResult( - content::BrowserThread::GetBlockingPool(), FROM_HERE, + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, base::TaskTraits().MayBlock().WithPriority( + base::TaskPriority::BACKGROUND), base::Bind(&CropImage, decoded_bitmap), base::Bind(&DownloadItemNotification::OnImageCropped, weak_factory_.GetWeakPtr()));
diff --git a/chrome/browser/engagement/important_sites_util.cc b/chrome/browser/engagement/important_sites_util.cc index cdb5ff7..c266bd0 100644 --- a/chrome/browser/engagement/important_sites_util.cc +++ b/chrome/browser/engagement/important_sites_util.cc
@@ -22,9 +22,13 @@ #include "chrome/browser/engagement/site_engagement_score.h" #include "chrome/browser/engagement/site_engagement_service.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/common/pref_names.h" #include "components/bookmarks/browser/bookmark_model.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/content_settings/core/common/content_settings.h" +#include "components/pref_registry/pref_registry_syncable.h" +#include "components/prefs/pref_service.h" +#include "components/prefs/scoped_user_pref_update.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" #include "third_party/WebKit/public/platform/site_engagement.mojom.h" #include "url/gurl.h" @@ -33,6 +37,12 @@ using bookmarks::BookmarkModel; using ImportantDomainInfo = ImportantSitesUtil::ImportantDomainInfo; +// Note: These values are stored on both the per-site content settings +// dictionary and the dialog preference dictionary. + +static const char kTimeLastIgnored[] = "TimeLastIgnored"; +static const int kBlacklistExpirationTimeDays = 30 * 5; + static const char kNumTimesIgnoredName[] = "NumTimesIgnored"; static const int kTimesIgnoredForBlacklist = 3; @@ -84,6 +94,31 @@ CROSSED_REASON_BOUNDARY }; +void RecordIgnore(base::DictionaryValue* dict) { + int times_ignored = 0; + dict->GetInteger(kNumTimesIgnoredName, ×_ignored); + dict->SetInteger(kNumTimesIgnoredName, ++times_ignored); + dict->SetDouble(kTimeLastIgnored, base::Time::Now().ToDoubleT()); +} + +// If we should blacklist the item with the given dictionary ignored record. +bool ShouldSuppressItem(base::DictionaryValue* dict) { + double last_ignored_time = 0; + if (dict->GetDouble(kTimeLastIgnored, &last_ignored_time)) { + base::TimeDelta diff = + base::Time::Now() - base::Time::FromDoubleT(last_ignored_time); + if (diff >= base::TimeDelta::FromDays(kBlacklistExpirationTimeDays)) { + dict->SetInteger(kNumTimesIgnoredName, 0); + dict->Remove(kTimeLastIgnored, nullptr); + return false; + } + } + + int times_ignored = 0; + return dict->GetInteger(kNumTimesIgnoredName, ×_ignored) && + times_ignored >= kTimesIgnoredForBlacklist; +} + CrossedReason GetCrossedReasonFromBitfield(int32_t reason_bitfield) { bool durable = (reason_bitfield & (1 << ImportantReason::DURABLE)) != 0; bool notifications = @@ -198,13 +233,8 @@ if (!dict) continue; - int times_ignored = 0; - if (!dict->GetInteger(kNumTimesIgnoredName, ×_ignored) || - times_ignored < kTimesIgnoredForBlacklist) { - continue; - } - - ignoring_domains.insert(origin.host()); + if (ShouldSuppressItem(dict.get())) + ignoring_domains.insert(origin.host()); } return ignoring_domains; } @@ -320,6 +350,18 @@ } // namespace +bool ImportantSitesUtil::IsDialogDisabled(Profile* profile) { + PrefService* service = profile->GetPrefs(); + DictionaryPrefUpdate update(service, prefs::kImportantSitesDialogHistory); + + return ShouldSuppressItem(update.Get()); +} + +void ImportantSitesUtil::RegisterProfilePrefs( + user_prefs::PrefRegistrySyncable* registry) { + registry->RegisterDictionaryPref(prefs::kImportantSitesDialogHistory); +} + std::vector<ImportantDomainInfo> ImportantSitesUtil::GetImportantRegisterableDomains(Profile* profile, size_t max_results) { @@ -385,36 +427,41 @@ "Storage.ImportantSites.CBDIgnoredReasonCount", reason_bitfield); } - // We use the ignored sites to update our important sites blacklist. HostContentSettingsMap* map = HostContentSettingsMapFactory::GetForProfile(profile); - for (const std::string& ignored_site : ignored_sites) { - GURL origin("http://" + ignored_site); - std::unique_ptr<base::Value> value = map->GetWebsiteSetting( - origin, origin, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "", nullptr); - std::unique_ptr<base::DictionaryValue> dict = - base::DictionaryValue::From(map->GetWebsiteSetting( - origin, origin, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "", - nullptr)); + // We use the ignored sites to update our important sites blacklist only if + // the user chose to blacklist a site. + if (!blacklisted_sites.empty()) { + for (const std::string& ignored_site : ignored_sites) { + GURL origin("http://" + ignored_site); + std::unique_ptr<base::DictionaryValue> dict = + base::DictionaryValue::From(map->GetWebsiteSetting( + origin, origin, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "", + nullptr)); - int times_ignored = 0; - if (dict) - dict->GetInteger(kNumTimesIgnoredName, ×_ignored); - else - dict = base::MakeUnique<base::DictionaryValue>(); - dict->SetInteger(kNumTimesIgnoredName, ++times_ignored); + if (!dict) + dict = base::MakeUnique<base::DictionaryValue>(); - map->SetWebsiteSettingDefaultScope( - origin, origin, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "", - std::move(dict)); + RecordIgnore(dict.get()); + + map->SetWebsiteSettingDefaultScope( + origin, origin, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "", + std::move(dict)); + } + } else { + // Record that the user did not interact with the dialog. + PrefService* service = profile->GetPrefs(); + DictionaryPrefUpdate update(service, prefs::kImportantSitesDialogHistory); + RecordIgnore(update.Get()); } // We clear our blacklist for sites that the user chose. - for (const std::string& ignored_site : blacklisted_sites) { - GURL origin("http://" + ignored_site); + for (const std::string& blacklisted_site : blacklisted_sites) { + GURL origin("http://" + blacklisted_site); std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); dict->SetInteger(kNumTimesIgnoredName, 0); + dict->Remove(kTimeLastIgnored, nullptr); map->SetWebsiteSettingDefaultScope( origin, origin, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "", std::move(dict));
diff --git a/chrome/browser/engagement/important_sites_util.h b/chrome/browser/engagement/important_sites_util.h index c625935..408dff05d 100644 --- a/chrome/browser/engagement/important_sites_util.h +++ b/chrome/browser/engagement/important_sites_util.h
@@ -13,6 +13,10 @@ class Profile; +namespace user_prefs { +class PrefRegistrySyncable; +} + class ImportantSitesUtil { public: struct ImportantDomainInfo { @@ -22,6 +26,10 @@ int32_t reason_bitfield = 0; }; + static bool IsDialogDisabled(Profile* profile); + + static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); + // This returns the top |<=max_results| important registrable domains. This // uses site engagement and notifications to generate the list. |max_results| // is assumed to be small.
diff --git a/chrome/browser/engagement/important_sites_util_unittest.cc b/chrome/browser/engagement/important_sites_util_unittest.cc index 224b08b..028eb7c 100644 --- a/chrome/browser/engagement/important_sites_util_unittest.cc +++ b/chrome/browser/engagement/important_sites_util_unittest.cc
@@ -258,10 +258,11 @@ ASSERT_TRUE(service); GURL url1("http://www.google.com/"); + GURL url2("http://www.gmail.com/"); // Set a bunch of positive signals. service->ResetScoreForURL(url1, 5); - AddBookmark(url1); + AddBookmark(url2); AddContentSetting(CONTENT_SETTINGS_TYPE_NOTIFICATIONS, CONTENT_SETTING_ALLOW, url1); @@ -269,17 +270,18 @@ std::vector<ImportantDomainInfo> important_sites = ImportantSitesUtil::GetImportantRegisterableDomains(profile(), kNumImportantSites); - std::vector<std::string> expected_sorted_domains = {"google.com"}; - std::vector<GURL> expected_sorted_origins = {url1}; + std::vector<std::string> expected_sorted_domains = {"google.com", + "gmail.com"}; + std::vector<GURL> expected_sorted_origins = {url1, url2}; ExpectImportantResultsEq(expected_sorted_domains, expected_sorted_origins, important_sites); - ASSERT_EQ(1u, important_sites.size()); + ASSERT_EQ(2u, important_sites.size()); // Record ignore twice. ImportantSitesUtil::RecordBlacklistedAndIgnoredImportantSites( - profile(), std::vector<std::string>(), std::vector<int32_t>(), + profile(), {"gmail.com"}, {important_sites[1].reason_bitfield}, {"google.com"}, {important_sites[0].reason_bitfield}); ImportantSitesUtil::RecordBlacklistedAndIgnoredImportantSites( - profile(), std::vector<std::string>(), std::vector<int32_t>(), + profile(), {"gmail.com"}, {important_sites[1].reason_bitfield}, {"google.com"}, {important_sites[0].reason_bitfield}); // Important fetch 2. @@ -288,17 +290,22 @@ ExpectImportantResultsEq(expected_sorted_domains, expected_sorted_origins, important_sites); // We shouldn't blacklist after first two times. - ASSERT_EQ(1u, important_sites.size()); + ASSERT_EQ(2u, important_sites.size()); // Record ignore 3rd time. ImportantSitesUtil::RecordBlacklistedAndIgnoredImportantSites( - profile(), std::vector<std::string>(), std::vector<int32_t>(), + profile(), {"gmail.com"}, {important_sites[1].reason_bitfield}, {"google.com"}, {important_sites[0].reason_bitfield}); - // Important fetch 3. We should be blacklisted now. + // Important fetch 3. Google.com should be blacklisted now. important_sites = ImportantSitesUtil::GetImportantRegisterableDomains( profile(), kNumImportantSites); - ASSERT_EQ(0u, important_sites.size()); + + ASSERT_EQ(1u, important_sites.size()); + expected_sorted_domains = {"gmail.com"}; + expected_sorted_origins = {url2}; + ExpectImportantResultsEq(expected_sorted_domains, expected_sorted_origins, + important_sites); } TEST_F(ImportantSitesUtilTest, BlacklistingReset) { @@ -306,46 +313,49 @@ ASSERT_TRUE(service); GURL url1("http://www.google.com/"); + GURL url2("http://www.gmail.com/"); // Set a bunch of positive signals. service->ResetScoreForURL(url1, 5); - AddBookmark(url1); + AddBookmark(url2); AddContentSetting(CONTENT_SETTINGS_TYPE_NOTIFICATIONS, CONTENT_SETTING_ALLOW, url1); + // Important fetch 1. std::vector<ImportantDomainInfo> important_sites = ImportantSitesUtil::GetImportantRegisterableDomains(profile(), kNumImportantSites); - - // Record ignored twice. - ASSERT_EQ(1u, important_sites.size()); + ASSERT_EQ(2u, important_sites.size()); + // Record ignore twice. ImportantSitesUtil::RecordBlacklistedAndIgnoredImportantSites( - profile(), std::vector<std::string>(), std::vector<int32_t>(), + profile(), {"gmail.com"}, {important_sites[1].reason_bitfield}, {"google.com"}, {important_sites[0].reason_bitfield}); ImportantSitesUtil::RecordBlacklistedAndIgnoredImportantSites( - profile(), std::vector<std::string>(), std::vector<int32_t>(), + profile(), {"gmail.com"}, {important_sites[1].reason_bitfield}, {"google.com"}, {important_sites[0].reason_bitfield}); // Important fetch, we should still be there. important_sites = ImportantSitesUtil::GetImportantRegisterableDomains( profile(), kNumImportantSites); - std::vector<std::string> expected_sorted_domains = {"google.com"}; - std::vector<GURL> expected_sorted_origins = {url1}; - ASSERT_EQ(1u, important_sites.size()); + std::vector<std::string> expected_sorted_domains = {"google.com", + "gmail.com"}; + std::vector<GURL> expected_sorted_origins = {url1, url2}; + ASSERT_EQ(2u, important_sites.size()); ExpectImportantResultsEq(expected_sorted_domains, expected_sorted_origins, important_sites); // Record NOT ignored. ImportantSitesUtil::RecordBlacklistedAndIgnoredImportantSites( - profile(), {"google.com"}, {important_sites[0].reason_bitfield}, + profile(), {"google.com", "gmail.com"}, + {important_sites[0].reason_bitfield, important_sites[1].reason_bitfield}, std::vector<std::string>(), std::vector<int32_t>()); - // Record ignored twice again. + // Record ignored twice again ImportantSitesUtil::RecordBlacklistedAndIgnoredImportantSites( - profile(), std::vector<std::string>(), std::vector<int32_t>(), + profile(), {"gmail.com"}, {important_sites[1].reason_bitfield}, {"google.com"}, {important_sites[0].reason_bitfield}); ImportantSitesUtil::RecordBlacklistedAndIgnoredImportantSites( - profile(), std::vector<std::string>(), std::vector<int32_t>(), + profile(), {"gmail.com"}, {important_sites[1].reason_bitfield}, {"google.com"}, {important_sites[0].reason_bitfield}); // Important fetch, we should still be there. @@ -356,13 +366,17 @@ // Record ignored 3rd time in a row. ImportantSitesUtil::RecordBlacklistedAndIgnoredImportantSites( - profile(), std::vector<std::string>(), std::vector<int32_t>(), + profile(), {"gmail.com"}, {important_sites[1].reason_bitfield}, {"google.com"}, {important_sites[0].reason_bitfield}); // Blacklisted now. important_sites = ImportantSitesUtil::GetImportantRegisterableDomains( profile(), kNumImportantSites); - EXPECT_EQ(0u, important_sites.size()); + ASSERT_EQ(1u, important_sites.size()); + expected_sorted_domains = {"gmail.com"}; + expected_sorted_origins = {url2}; + ExpectImportantResultsEq(expected_sorted_domains, expected_sorted_origins, + important_sites); } TEST_F(ImportantSitesUtilTest, Metrics) { @@ -407,3 +421,58 @@ base::Bucket(CROSSED_NOTIFICATIONS_AND_ENGAGEMENT, 1), base::Bucket(CROSSED_REASON_UNKNOWN, 1))); } + +TEST_F(ImportantSitesUtilTest, DialogBlacklisting) { + SiteEngagementService* service = SiteEngagementService::Get(profile()); + ASSERT_TRUE(service); + + GURL url1("http://www.google.com/"); + GURL url2("http://www.yahoo.com/"); + + // Set a bunch of positive signals. + service->ResetScoreForURL(url2, 5); + AddBookmark(url1); + AddContentSetting(CONTENT_SETTINGS_TYPE_NOTIFICATIONS, CONTENT_SETTING_ALLOW, + url1); + + // Start off not disabled. + EXPECT_FALSE(ImportantSitesUtil::IsDialogDisabled(profile())); + + // Important fetch 1. + std::vector<ImportantDomainInfo> important_sites = + ImportantSitesUtil::GetImportantRegisterableDomains(profile(), + kNumImportantSites); + std::vector<std::string> expected_sorted_domains = {"google.com", + "yahoo.com"}; + std::vector<GURL> expected_sorted_origins = {url1, url2}; + ExpectImportantResultsEq(expected_sorted_domains, expected_sorted_origins, + important_sites); + ASSERT_EQ(2u, important_sites.size()); + // Ignore all sites 2 times. + ImportantSitesUtil::RecordBlacklistedAndIgnoredImportantSites( + profile(), std::vector<std::string>(), std::vector<int32_t>(), + {"google.com", "yahoo.com"}, + {important_sites[0].reason_bitfield, important_sites[1].reason_bitfield}); + ImportantSitesUtil::RecordBlacklistedAndIgnoredImportantSites( + profile(), std::vector<std::string>(), std::vector<int32_t>(), + {"google.com", "yahoo.com"}, + {important_sites[0].reason_bitfield, important_sites[1].reason_bitfield}); + + // Still not disabled... + EXPECT_FALSE(ImportantSitesUtil::IsDialogDisabled(profile())); + + // Ignore 3rd time. + ImportantSitesUtil::RecordBlacklistedAndIgnoredImportantSites( + profile(), std::vector<std::string>(), std::vector<int32_t>(), + {"google.com", "yahoo.com"}, + {important_sites[0].reason_bitfield, important_sites[1].reason_bitfield}); + + // Items should still be present. + important_sites = ImportantSitesUtil::GetImportantRegisterableDomains( + profile(), kNumImportantSites); + ExpectImportantResultsEq(expected_sorted_domains, expected_sorted_origins, + important_sites); + + // Dialog should be blacklisted. + EXPECT_TRUE(ImportantSitesUtil::IsDialogDisabled(profile())); +}
diff --git a/chrome/browser/extensions/api/browsing_data/OWNERS b/chrome/browser/extensions/api/browsing_data/OWNERS index 59099fbe..a56cd7f 100644 --- a/chrome/browser/extensions/api/browsing_data/OWNERS +++ b/chrome/browser/extensions/api/browsing_data/OWNERS
@@ -2,3 +2,5 @@ # but the following people are the most knowledgable: bauerb@chromium.org mkwst@chromium.org + +# COMPONENT: Platform>Extensions>API
diff --git a/chrome/browser/extensions/api/cookies/OWNERS b/chrome/browser/extensions/api/cookies/OWNERS index 3f84563..1282f89 100644 --- a/chrome/browser/extensions/api/cookies/OWNERS +++ b/chrome/browser/extensions/api/cookies/OWNERS
@@ -1 +1,3 @@ mkwst@chromium.org + +# COMPONENT: Platform>Extensions>API
diff --git a/chrome/browser/extensions/api/processes/processes_api.cc b/chrome/browser/extensions/api/processes/processes_api.cc index fe04129..1a928f5 100644 --- a/chrome/browser/extensions/api/processes/processes_api.cc +++ b/chrome/browser/extensions/api/processes/processes_api.cc
@@ -25,7 +25,7 @@ #include "content/public/common/child_process_host.h" #include "content/public/common/result_codes.h" #include "extensions/common/error_utils.h" -#include "third_party/WebKit/public/web/WebCache.h" +#include "third_party/WebKit/public/platform/WebCache.h" namespace extensions {
diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc index f1ef9c0..163ebfb5 100644 --- a/chrome/browser/extensions/extension_tab_util.cc +++ b/chrome/browser/extensions/extension_tab_util.cc
@@ -441,23 +441,24 @@ void ExtensionTabUtil::ScrubTabForExtension(const Extension* extension, content::WebContents* contents, api::tabs::Tab* tab) { - DCHECK(extension); - - bool api_permission = false; - std::string url; - if (contents) { - api_permission = extension->permissions_data()->HasAPIPermissionForTab( - GetTabId(contents), APIPermission::kTab); - url = contents->GetURL().spec(); - } else { - api_permission = - extension->permissions_data()->HasAPIPermission(APIPermission::kTab); - url = *tab->url; + bool has_permission = false; + if (extension) { + bool api_permission = false; + std::string url; + if (contents) { + api_permission = extension->permissions_data()->HasAPIPermissionForTab( + GetTabId(contents), APIPermission::kTab); + url = contents->GetURL().spec(); + } else { + api_permission = + extension->permissions_data()->HasAPIPermission(APIPermission::kTab); + url = *tab->url; + } + bool host_permission = extension->permissions_data() + ->active_permissions() + .HasExplicitAccessToOrigin(GURL(url)); + has_permission = api_permission || host_permission; } - bool host_permission = extension->permissions_data() - ->active_permissions() - .HasExplicitAccessToOrigin(GURL(url)); - bool has_permission = api_permission || host_permission; if (!has_permission) { tab->url.reset(); tab->title.reset();
diff --git a/chrome/browser/external_protocol/external_protocol_handler.cc b/chrome/browser/external_protocol/external_protocol_handler.cc index 96206ed..29f98ed 100644 --- a/chrome/browser/external_protocol/external_protocol_handler.cc +++ b/chrome/browser/external_protocol/external_protocol_handler.cc
@@ -134,6 +134,11 @@ } // namespace +const char ExternalProtocolHandler::kRememberCheckboxMetric[] = + "BrowserDialogs.ExternalProtocol.RememberCheckbox"; +const char ExternalProtocolHandler::kHandleStateMetric[] = + "BrowserDialogs.ExternalProtocol.HandleState"; + // static ExternalProtocolHandler::BlockState ExternalProtocolHandler::GetBlockState( const std::string& scheme, @@ -313,9 +318,27 @@ } // static -void ExternalProtocolHandler::RecordMetrics(bool selected) { - UMA_HISTOGRAM_BOOLEAN("BrowserDialogs.ExternalProtocol.RememberCheckbox", - selected); +void ExternalProtocolHandler::RecordCheckboxStateMetrics(bool selected) { + UMA_HISTOGRAM_BOOLEAN(kRememberCheckboxMetric, selected); +} + +// static +void ExternalProtocolHandler::RecordHandleStateMetrics(bool checkbox_selected, + BlockState block_state) { + HandleState handle_state = DONT_LAUNCH; + switch (block_state) { + case DONT_BLOCK: + handle_state = checkbox_selected ? CHECKED_LAUNCH : LAUNCH; + break; + case BLOCK: + handle_state = checkbox_selected ? CHECKED_DONT_LAUNCH : DONT_LAUNCH; + break; + case UNKNOWN: + NOTREACHED(); + return; + } + UMA_HISTOGRAM_ENUMERATION(kHandleStateMetric, handle_state, + HANDLE_STATE_LAST); } // static
diff --git a/chrome/browser/external_protocol/external_protocol_handler.h b/chrome/browser/external_protocol/external_protocol_handler.h index e70e79bb..30a1600 100644 --- a/chrome/browser/external_protocol/external_protocol_handler.h +++ b/chrome/browser/external_protocol/external_protocol_handler.h
@@ -28,6 +28,17 @@ UNKNOWN, }; + // This is used to back a UMA histogram, so it should be treated as + // append-only. Any new values should be inserted immediately prior to + // HANDLE_STATE_LAST. + enum HandleState { + LAUNCH, + CHECKED_LAUNCH, + DONT_LAUNCH, + CHECKED_DONT_LAUNCH, + HANDLE_STATE_LAST + }; + // Delegate to allow unit testing to provide different behavior. class Delegate { public: @@ -51,6 +62,10 @@ virtual ~Delegate() {} }; + // UMA histogram metric names. + static const char kRememberCheckboxMetric[]; + static const char kHandleStateMetric[]; + // Returns whether we should block a given scheme. static BlockState GetBlockState(const std::string& scheme, Profile* profile); @@ -97,7 +112,12 @@ // Records an UMA metric for the state of the checkbox in the dialog, i.e. // whether |selected| is true (checked) or false (unchecked). - static void RecordMetrics(bool selected); + static void RecordCheckboxStateMetrics(bool selected); + + // Records an UMA metric for the external protocol HandleState selected, based + // on if the check box is selected / not and block / Dont block is picked. + static void RecordHandleStateMetrics(bool checkbox_selected, + BlockState state); // Register the ExcludedSchemes preference. static void RegisterPrefs(PrefRegistrySimple* registry);
diff --git a/chrome/browser/gcm/OWNERS b/chrome/browser/gcm/OWNERS index af1d4150..3cba11c 100644 --- a/chrome/browser/gcm/OWNERS +++ b/chrome/browser/gcm/OWNERS
@@ -3,3 +3,5 @@ jianli@chromium.org peter@chromium.org zea@chromium.org + +# COMPONENT: Services>CloudMessaging
diff --git a/chrome/browser/lifetime/application_lifetime.cc b/chrome/browser/lifetime/application_lifetime.cc index 44eee4a..e6578f0 100644 --- a/chrome/browser/lifetime/application_lifetime.cc +++ b/chrome/browser/lifetime/application_lifetime.cc
@@ -46,10 +46,13 @@ #if defined(OS_CHROMEOS) #include "base/sys_info.h" #include "chrome/browser/chromeos/boot_times_recorder.h" +#include "chrome/browser/chromeos/settings/cros_settings.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/power_policy_controller.h" #include "chromeos/dbus/session_manager_client.h" #include "chromeos/dbus/update_engine_client.h" +#include "chromeos/settings/cros_settings_names.h" +#include "ui/base/l10n/l10n_util.h" #endif #if defined(OS_WIN) @@ -83,6 +86,34 @@ #endif // !defined(OS_ANDROID) #if defined(OS_CHROMEOS) +// Sets kApplicationLocale in |local_state| for the login screen on the next +// application start, if it is forced to a specific value due to enterprise +// policy or the owner's locale. Returns true if any pref has been modified. +bool SetLocaleForNextStart(PrefService* local_state) { + // If a policy mandates the login screen locale, use it. + chromeos::CrosSettings* cros_settings = chromeos::CrosSettings::Get(); + const base::ListValue* login_screen_locales = nullptr; + std::string login_screen_locale; + if (cros_settings->GetList(chromeos::kDeviceLoginScreenLocales, + &login_screen_locales) && + !login_screen_locales->empty() && + login_screen_locales->GetString(0, &login_screen_locale)) { + local_state->SetString(prefs::kApplicationLocale, login_screen_locale); + return true; + } + + // Login screen should show up in owner's locale. + std::string owner_locale = local_state->GetString(prefs::kOwnerLocale); + if (!owner_locale.empty() && + local_state->GetString(prefs::kApplicationLocale) != owner_locale && + !local_state->IsManagedPreference(prefs::kApplicationLocale)) { + local_state->SetString(prefs::kApplicationLocale, owner_locale); + return true; + } + + return false; +} + // Whether chrome should send stop request to a session manager. bool g_send_stop_request_to_session_manager = false; #endif @@ -168,12 +199,7 @@ if (state) { chromeos::BootTimesRecorder::Get()->OnLogoutStarted(state); - // Login screen should show up in owner's locale. - std::string owner_locale = state->GetString(prefs::kOwnerLocale); - if (!owner_locale.empty() && - state->GetString(prefs::kApplicationLocale) != owner_locale && - !state->IsManagedPreference(prefs::kApplicationLocale)) { - state->SetString(prefs::kApplicationLocale, owner_locale); + if (SetLocaleForNextStart(state)) { TRACE_EVENT0("shutdown", "CommitPendingWrite"); state->CommitPendingWrite(); }
diff --git a/chrome/browser/media/android/router/media_router_android.cc b/chrome/browser/media/android/router/media_router_android.cc index 9fa7aa6..62e132b 100644 --- a/chrome/browser/media/android/router/media_router_android.cc +++ b/chrome/browser/media/android/router/media_router_android.cc
@@ -75,20 +75,12 @@ void MediaRouterAndroid::CreateRoute( const MediaSource::Id& source_id, const MediaSink::Id& sink_id, - const GURL& origin, + const url::Origin& origin, content::WebContents* web_contents, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout, bool incognito) { // TODO(avayvod): Implement timeouts (crbug.com/583036). - if (!origin.is_valid()) { - std::unique_ptr<RouteRequestResult> result = RouteRequestResult::FromError( - "Invalid origin", RouteRequestResult::INVALID_ORIGIN); - for (const MediaRouteResponseCallback& callback : callbacks) - callback.Run(*result); - return; - } - std::string presentation_id = MediaRouterBase::CreatePresentationId(); int tab_id = -1; @@ -111,8 +103,10 @@ base::android::ConvertUTF8ToJavaString(env, sink_id); ScopedJavaLocalRef<jstring> jpresentation_id = base::android::ConvertUTF8ToJavaString(env, presentation_id); + // TODO(crbug.com/685358): Unique origins should not be considered + // same-origin. ScopedJavaLocalRef<jstring> jorigin = - base::android::ConvertUTF8ToJavaString(env, origin.spec()); + base::android::ConvertUTF8ToJavaString(env, origin.GetURL().spec()); Java_ChromeMediaRouter_createRoute(env, java_media_router_, jsource_id, jsink_id, jpresentation_id, jorigin, @@ -122,7 +116,7 @@ void MediaRouterAndroid::ConnectRouteByRouteId( const MediaSource::Id& source, const MediaRoute::Id& route_id, - const GURL& origin, + const url::Origin& origin, content::WebContents* web_contents, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout, @@ -133,20 +127,12 @@ void MediaRouterAndroid::JoinRoute( const MediaSource::Id& source_id, const std::string& presentation_id, - const GURL& origin, + const url::Origin& origin, content::WebContents* web_contents, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout, bool incognito) { // TODO(avayvod): Implement timeouts (crbug.com/583036). - if (!origin.is_valid()) { - std::unique_ptr<RouteRequestResult> result = RouteRequestResult::FromError( - "Invalid origin", RouteRequestResult::INVALID_ORIGIN); - for (const MediaRouteResponseCallback& callback : callbacks) - callback.Run(*result); - return; - } - int tab_id = -1; TabAndroid* tab = web_contents ? TabAndroid::FromWebContents(web_contents) : nullptr; @@ -154,7 +140,7 @@ tab_id = tab->GetAndroidId(); DVLOG(2) << "JoinRoute: " << source_id << ", " << presentation_id << ", " - << origin.spec() << ", " << tab_id; + << origin.GetURL().spec() << ", " << tab_id; int request_id = route_requests_.Add(base::MakeUnique<MediaRouteRequest>( MediaSource(source_id), presentation_id, callbacks)); @@ -165,7 +151,7 @@ ScopedJavaLocalRef<jstring> jpresentation_id = base::android::ConvertUTF8ToJavaString(env, presentation_id); ScopedJavaLocalRef<jstring> jorigin = - base::android::ConvertUTF8ToJavaString(env, origin.spec()); + base::android::ConvertUTF8ToJavaString(env, origin.GetURL().spec()); Java_ChromeMediaRouter_joinRoute(env, java_media_router_, jsource_id, jpresentation_id, jorigin, tab_id, @@ -348,7 +334,7 @@ if (it != sinks_observers_.end()) { // TODO(imcheng): Pass origins to OnSinksUpdated (crbug.com/594858). for (auto& observer : *it->second) - observer.OnSinksUpdated(sinks_converted, std::vector<GURL>()); + observer.OnSinksUpdated(sinks_converted, std::vector<url::Origin>()); } }
diff --git a/chrome/browser/media/android/router/media_router_android.h b/chrome/browser/media/android/router/media_router_android.h index 592c953..b30b4cc 100644 --- a/chrome/browser/media/android/router/media_router_android.h +++ b/chrome/browser/media/android/router/media_router_android.h
@@ -35,14 +35,14 @@ // MediaRouter implementation. void CreateRoute(const MediaSource::Id& source_id, const MediaSink::Id& sink_id, - const GURL& origin, + const url::Origin& origin, content::WebContents* web_contents, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout, bool incognito) override; void JoinRoute(const MediaSource::Id& source, const std::string& presentation_id, - const GURL& origin, + const url::Origin& origin, content::WebContents* web_contents, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout, @@ -50,7 +50,7 @@ void ConnectRouteByRouteId( const MediaSource::Id& source, const MediaRoute::Id& route_id, - const GURL& origin, + const url::Origin& origin, content::WebContents* web_contents, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout,
diff --git a/chrome/browser/media/android/router/media_router_dialog_controller_android.cc b/chrome/browser/media/android/router/media_router_dialog_controller_android.cc index 44296df5..9da67346 100644 --- a/chrome/browser/media/android/router/media_router_dialog_controller_android.cc +++ b/chrome/browser/media/android/router/media_router_dialog_controller_android.cc
@@ -53,7 +53,7 @@ // TODO(crbug.com/627655): Support multiple URLs. const MediaSource::Id source_id = presentation_request.GetMediaSources()[0].id(); - const GURL origin = presentation_request.frame_url().GetOrigin(); + const auto& origin = presentation_request.frame_origin(); std::vector<MediaRouteResponseCallback> route_response_callbacks; route_response_callbacks.push_back(
diff --git a/chrome/browser/media/router/BUILD.gn b/chrome/browser/media/router/BUILD.gn index a5ef137..18f8f67 100644 --- a/chrome/browser/media/router/BUILD.gn +++ b/chrome/browser/media/router/BUILD.gn
@@ -104,6 +104,7 @@ public_deps = [ "//mojo/common:common_custom_types", + "//url/mojo:url_mojom_origin", ] }
diff --git a/chrome/browser/media/router/create_presentation_connection_request.cc b/chrome/browser/media/router/create_presentation_connection_request.cc index 9dd49c9..49eb3ed 100644 --- a/chrome/browser/media/router/create_presentation_connection_request.cc +++ b/chrome/browser/media/router/create_presentation_connection_request.cc
@@ -6,7 +6,7 @@ #include "chrome/browser/media/router/media_source_helper.h" #include "chrome/browser/media/router/route_request_result.h" -#include "url/gurl.h" +#include "url/origin.h" using content::PresentationSessionInfo; using content::PresentationError; @@ -16,10 +16,12 @@ CreatePresentationConnectionRequest::CreatePresentationConnectionRequest( const RenderFrameHostId& render_frame_host_id, const std::vector<GURL>& presentation_urls, - const GURL& frame_url, + const url::Origin& frame_origin, const PresentationSessionSuccessCallback& success_cb, const PresentationSessionErrorCallback& error_cb) - : presentation_request_(render_frame_host_id, presentation_urls, frame_url), + : presentation_request_(render_frame_host_id, + presentation_urls, + frame_origin), success_cb_(success_cb), error_cb_(error_cb), cb_invoked_(false) {
diff --git a/chrome/browser/media/router/create_presentation_connection_request.h b/chrome/browser/media/router/create_presentation_connection_request.h index 41e5da49..dc702af 100644 --- a/chrome/browser/media/router/create_presentation_connection_request.h +++ b/chrome/browser/media/router/create_presentation_connection_request.h
@@ -16,13 +16,15 @@ #include "chrome/browser/media/router/render_frame_host_id.h" #include "content/public/browser/presentation_service_delegate.h" -class GURL; - namespace content { struct PresentationError; struct PresentationSessionInfo; } // namespace content +namespace url { +class Origin; +} // namespace url + namespace media_router { class RouteRequestResult; @@ -42,13 +44,14 @@ content::PresentationSessionErrorCallback; // |presentation_url|: The presentation URL of the request. Must be a valid // URL. - // |frame_url|: The URL of the frame that initiated the presentation request. + // |frame_origin|: The origin of the frame that initiated the presentation + // request. // |success_cb|: Callback to invoke when the request succeeds. Must be valid. // |erorr_cb|: Callback to invoke when the request fails. Must be valid. CreatePresentationConnectionRequest( const RenderFrameHostId& render_frame_host_id, const std::vector<GURL>& presentation_urls, - const GURL& frame_url, + const url::Origin& frame_origin, const PresentationSessionSuccessCallback& success_cb, const PresentationSessionErrorCallback& error_cb); ~CreatePresentationConnectionRequest();
diff --git a/chrome/browser/media/router/create_presentation_connection_request_unittest.cc b/chrome/browser/media/router/create_presentation_connection_request_unittest.cc index 8e71ecb4..6c373b9f 100644 --- a/chrome/browser/media/router/create_presentation_connection_request_unittest.cc +++ b/chrome/browser/media/router/create_presentation_connection_request_unittest.cc
@@ -68,14 +68,14 @@ content::PresentationError error(content::PRESENTATION_ERROR_UNKNOWN, "Unknown error."); CreatePresentationConnectionRequest request( - render_frame_host_id_, presentation_urls_, GURL(kFrameUrl), + render_frame_host_id_, presentation_urls_, url::Origin(GURL(kFrameUrl)), base::Bind(&CreatePresentationConnectionRequestTest::FailOnSuccess, base::Unretained(this)), base::Bind(&CreatePresentationConnectionRequestTest::OnError, base::Unretained(this), error)); - PresentationRequest presentation_request(render_frame_host_id_, - presentation_urls_, GURL(kFrameUrl)); + PresentationRequest presentation_request( + render_frame_host_id_, presentation_urls_, url::Origin(GURL(kFrameUrl))); EXPECT_TRUE(request.presentation_request().Equals(presentation_request)); // Since we didn't explicitly call Invoke*, the error callback will be // invoked when |request| is destroyed. @@ -85,7 +85,7 @@ content::PresentationSessionInfo session_info(presentation_url_, kPresentationId); CreatePresentationConnectionRequest request( - render_frame_host_id_, {presentation_url_}, GURL(kFrameUrl), + render_frame_host_id_, {presentation_url_}, url::Origin(GURL(kFrameUrl)), base::Bind(&CreatePresentationConnectionRequestTest::OnSuccess, base::Unretained(this), session_info), base::Bind(&CreatePresentationConnectionRequestTest::FailOnError, @@ -101,7 +101,7 @@ content::PRESENTATION_ERROR_SESSION_REQUEST_CANCELLED, "This is an error message"); CreatePresentationConnectionRequest request( - render_frame_host_id_, presentation_urls_, GURL(kFrameUrl), + render_frame_host_id_, presentation_urls_, url::Origin(GURL(kFrameUrl)), base::Bind(&CreatePresentationConnectionRequestTest::FailOnSuccess, base::Unretained(this)), base::Bind(&CreatePresentationConnectionRequestTest::OnError,
diff --git a/chrome/browser/media/router/media_router.h b/chrome/browser/media/router/media_router.h index 92d6d068..0f8fd4b 100644 --- a/chrome/browser/media/router/media_router.h +++ b/chrome/browser/media/router/media_router.h
@@ -26,6 +26,10 @@ class WebContents; } +namespace url { +class Origin; +} // namespace url + namespace media_router { class IssuesObserver; @@ -78,7 +82,7 @@ virtual void CreateRoute( const MediaSource::Id& source_id, const MediaSink::Id& sink_id, - const GURL& origin, + const url::Origin& origin, content::WebContents* web_contents, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout, @@ -100,7 +104,7 @@ virtual void ConnectRouteByRouteId( const MediaSource::Id& source_id, const MediaRoute::Id& route_id, - const GURL& origin, + const url::Origin& origin, content::WebContents* web_contents, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout, @@ -120,7 +124,7 @@ virtual void JoinRoute( const MediaSource::Id& source, const std::string& presentation_id, - const GURL& origin, + const url::Origin& origin, content::WebContents* web_contents, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout,
diff --git a/chrome/browser/media/router/media_router_dialog_controller_unittest.cc b/chrome/browser/media/router/media_router_dialog_controller_unittest.cc index a8f3d0e7..1baa12e 100644 --- a/chrome/browser/media/router/media_router_dialog_controller_unittest.cc +++ b/chrome/browser/media/router/media_router_dialog_controller_unittest.cc
@@ -70,7 +70,7 @@ new CreatePresentationConnectionRequest( RenderFrameHostId(1, 2), {GURL("http://example.com"), GURL("http://example2.com")}, - GURL("http://google.com"), + url::Origin(GURL("http://google.com")), base::Bind(&MediaRouterDialogControllerTest::RequestSuccess, base::Unretained(this)), base::Bind(&MediaRouterDialogControllerTest::RequestError,
diff --git a/chrome/browser/media/router/media_sinks_observer.cc b/chrome/browser/media/router/media_sinks_observer.cc index 61bb1096f..e7276fe5 100644 --- a/chrome/browser/media/router/media_sinks_observer.cc +++ b/chrome/browser/media/router/media_sinks_observer.cc
@@ -16,7 +16,7 @@ MediaSinksObserver::MediaSinksObserver(MediaRouter* router, const MediaSource& source, - const GURL& origin) + const url::Origin& origin) : source_(source), origin_(origin), router_(router), initialized_(false) { DCHECK(router_); } @@ -38,8 +38,9 @@ return initialized_; } -void MediaSinksObserver::OnSinksUpdated(const std::vector<MediaSink>& sinks, - const std::vector<GURL>& origins) { +void MediaSinksObserver::OnSinksUpdated( + const std::vector<MediaSink>& sinks, + const std::vector<url::Origin>& origins) { #if DCHECK_IS_ON() base::AutoReset<bool> reset_in_on_sinks_updated(&in_on_sinks_updated_, true); #endif
diff --git a/chrome/browser/media/router/media_sinks_observer.h b/chrome/browser/media/router/media_sinks_observer.h index 5a87f27..91741ab 100644 --- a/chrome/browser/media/router/media_sinks_observer.h +++ b/chrome/browser/media/router/media_sinks_observer.h
@@ -10,7 +10,7 @@ #include "base/macros.h" #include "chrome/browser/media/router/media_sink.h" #include "chrome/browser/media/router/media_source.h" -#include "url/gurl.h" +#include "url/origin.h" namespace media_router { @@ -28,7 +28,7 @@ // with |source|. MediaSinksObserver(MediaRouter* router, const MediaSource& source, - const GURL& origin); + const url::Origin& origin); virtual ~MediaSinksObserver(); // Registers with MediaRouter to start observing. Must be called before the @@ -42,7 +42,7 @@ // will be invoked with |sinks|. Otherwise, it will be invoked with an empty // list. void OnSinksUpdated(const std::vector<MediaSink>& sinks, - const std::vector<GURL>& origins); + const std::vector<url::Origin>& origins); const MediaSource& source() const { return source_; } @@ -55,7 +55,7 @@ private: const MediaSource source_; - const GURL origin_; + const url::Origin origin_; MediaRouter* const router_; bool initialized_;
diff --git a/chrome/browser/media/router/media_sinks_observer_unittest.cc b/chrome/browser/media/router/media_sinks_observer_unittest.cc index c5a340c..cbcc83a 100644 --- a/chrome/browser/media/router/media_sinks_observer_unittest.cc +++ b/chrome/browser/media/router/media_sinks_observer_unittest.cc
@@ -14,9 +14,8 @@ MockMediaRouter router; MediaSource source( MediaSourceForPresentationUrl(GURL("https://presentation.com"))); - GURL origin("https://origin.com"); - std::vector<GURL> origin_list; - origin_list.push_back(origin); + url::Origin origin{GURL("https://origin.com")}; + std::vector<url::Origin> origin_list({origin}); std::vector<MediaSink> sink_list; sink_list.push_back(MediaSink("sinkId", "Sink", MediaSink::IconType::CAST)); MockMediaSinksObserver observer(&router, source, origin); @@ -25,9 +24,9 @@ observer.OnSinksUpdated(sink_list, origin_list); EXPECT_CALL(observer, OnSinksReceived(SequenceEquals(sink_list))); - observer.OnSinksUpdated(sink_list, std::vector<GURL>()); + observer.OnSinksUpdated(sink_list, std::vector<url::Origin>()); - GURL origin2("https://differentOrigin.com"); + url::Origin origin2{GURL("https://differentOrigin.com")}; origin_list.clear(); origin_list.push_back(origin2); EXPECT_CALL(observer, OnSinksReceived(testing::IsEmpty()));
diff --git a/chrome/browser/media/router/mock_media_router.h b/chrome/browser/media/router/mock_media_router.h index f2d6ae4f..5fe951b 100644 --- a/chrome/browser/media/router/mock_media_router.h +++ b/chrome/browser/media/router/mock_media_router.h
@@ -16,6 +16,7 @@ #include "chrome/browser/media/router/media_sink.h" #include "chrome/browser/media/router/media_source.h" #include "testing/gmock/include/gmock/gmock.h" +#include "url/origin.h" namespace media_router { @@ -28,7 +29,7 @@ MOCK_METHOD7(CreateRoute, void(const MediaSource::Id& source, const MediaSink::Id& sink_id, - const GURL& origin, + const url::Origin& origin, content::WebContents* web_contents, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout, @@ -36,7 +37,7 @@ MOCK_METHOD7(JoinRoute, void(const MediaSource::Id& source, const std::string& presentation_id, - const GURL& origin, + const url::Origin& origin, content::WebContents* web_contents, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout, @@ -44,7 +45,7 @@ MOCK_METHOD7(ConnectRouteByRouteId, void(const MediaSource::Id& source, const MediaRoute::Id& route_id, - const GURL& origin, + const url::Origin& origin, content::WebContents* web_contents, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout,
diff --git a/chrome/browser/media/router/mojo/media_router.mojom b/chrome/browser/media/router/mojo/media_router.mojom index e26170d..37fc064 100644 --- a/chrome/browser/media/router/mojo/media_router.mojom +++ b/chrome/browser/media/router/mojo/media_router.mojom
@@ -5,6 +5,7 @@ module media_router.mojom; import "mojo/common/time.mojom"; +import "url/mojo/origin.mojom"; // Represents an output sink to which media can be routed. struct MediaSink { @@ -170,7 +171,7 @@ CreateRoute(string media_source, string sink_id, string original_presentation_id, - string origin, + url.mojom.Origin origin, int32 tab_id, mojo.common.mojom.TimeDelta timeout, bool incognito) => @@ -198,7 +199,7 @@ // occurred. JoinRoute(string media_source, string presentation_id, - string origin, + url.mojom.Origin origin, int32 tab_id, mojo.common.mojom.TimeDelta timeout, bool incognito) => @@ -232,7 +233,7 @@ ConnectRouteByRouteId(string media_source, string route_id, string presentation_id, - string origin, + url.mojom.Origin origin, int32 tab_id, mojo.common.mojom.TimeDelta timeout, bool incognito) => @@ -363,7 +364,7 @@ // compatible with |media_source|. The result is only valid for |origins|. If // |origins| is empty, the result is valid for any origin. OnSinksReceived(string media_source, array<MediaSink> sinks, - array<string> origins); + array<url.mojom.Origin> origins); // Called when issues are reported for media routes. OnIssue(Issue issue);
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc index 91c840d..fc356db6 100644 --- a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc +++ b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
@@ -176,7 +176,7 @@ void MediaRouterMojoImpl::OnSinksReceived( const std::string& media_source, std::vector<mojom::MediaSinkPtr> sinks, - const std::vector<std::string>& origins) { + const std::vector<url::Origin>& origins) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DVLOG_WITH_INSTANCE(1) << "OnSinksReceived"; auto it = sinks_queries_.find(media_source); @@ -185,18 +185,6 @@ return; } - std::vector<GURL> origin_list; - origin_list.reserve(origins.size()); - for (size_t i = 0; i < origins.size(); ++i) { - GURL origin(origins[i]); - if (!origin.is_valid()) { - LOG(WARNING) << "Received invalid origin: " << origin - << ". Dropping result."; - return; - } - origin_list.push_back(origin); - } - std::vector<MediaSink> sink_list; sink_list.reserve(sinks.size()); for (size_t i = 0; i < sinks.size(); ++i) @@ -204,7 +192,7 @@ auto* sinks_query = it->second.get(); sinks_query->has_cached_result = true; - sinks_query->origins.swap(origin_list); + sinks_query->origins = origins; sinks_query->cached_sink_list.swap(sink_list); if (!sinks_query->observers.might_have_observers()) { @@ -279,55 +267,36 @@ void MediaRouterMojoImpl::CreateRoute( const MediaSource::Id& source_id, const MediaSink::Id& sink_id, - const GURL& origin, + const url::Origin& origin, content::WebContents* web_contents, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout, bool incognito) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - if (!origin.is_valid()) { - DVLOG_WITH_INSTANCE(1) << "Invalid origin: " << origin; - std::unique_ptr<RouteRequestResult> result = RouteRequestResult::FromError( - "Invalid origin", RouteRequestResult::INVALID_ORIGIN); - MediaRouterMojoMetrics::RecordCreateRouteResultCode(result->result_code()); - RunRouteRequestCallbacks(std::move(result), callbacks); - return; - } - SetWakeReason(MediaRouteProviderWakeReason::CREATE_ROUTE); int tab_id = SessionTabHelper::IdForTab(web_contents); RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoCreateRoute, - base::Unretained(this), source_id, sink_id, - origin.is_empty() ? "" : origin.spec(), tab_id, - callbacks, timeout, incognito)); + base::Unretained(this), source_id, sink_id, origin, + tab_id, callbacks, timeout, incognito)); } void MediaRouterMojoImpl::JoinRoute( const MediaSource::Id& source_id, const std::string& presentation_id, - const GURL& origin, + const url::Origin& origin, content::WebContents* web_contents, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout, bool incognito) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - std::unique_ptr<RouteRequestResult> error_result; - if (!origin.is_valid()) { - DVLOG_WITH_INSTANCE(1) << "Invalid origin: " << origin; - error_result = RouteRequestResult::FromError( - "Invalid origin", RouteRequestResult::INVALID_ORIGIN); - } else if (!HasJoinableRoute()) { + if (!HasJoinableRoute()) { DVLOG_WITH_INSTANCE(1) << "No joinable routes"; - error_result = RouteRequestResult::FromError( + std::unique_ptr<RouteRequestResult> result = RouteRequestResult::FromError( "Route not found", RouteRequestResult::ROUTE_NOT_FOUND); - } - - if (error_result) { - MediaRouterMojoMetrics::RecordJoinRouteResultCode( - error_result->result_code()); - RunRouteRequestCallbacks(std::move(error_result), callbacks); + MediaRouterMojoMetrics::RecordJoinRouteResultCode(result->result_code()); + RunRouteRequestCallbacks(std::move(result), callbacks); return; } @@ -335,35 +304,24 @@ int tab_id = SessionTabHelper::IdForTab(web_contents); RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoJoinRoute, base::Unretained(this), source_id, presentation_id, - origin.is_empty() ? "" : origin.spec(), tab_id, - callbacks, timeout, incognito)); + origin, tab_id, callbacks, timeout, incognito)); } void MediaRouterMojoImpl::ConnectRouteByRouteId( const MediaSource::Id& source_id, const MediaRoute::Id& route_id, - const GURL& origin, + const url::Origin& origin, content::WebContents* web_contents, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout, bool incognito) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - if (!origin.is_valid()) { - DVLOG_WITH_INSTANCE(1) << "Invalid origin: " << origin; - std::unique_ptr<RouteRequestResult> result = RouteRequestResult::FromError( - "Invalid origin", RouteRequestResult::INVALID_ORIGIN); - MediaRouterMojoMetrics::RecordJoinRouteResultCode(result->result_code()); - RunRouteRequestCallbacks(std::move(result), callbacks); - return; - } - SetWakeReason(MediaRouteProviderWakeReason::CONNECT_ROUTE_BY_ROUTE_ID); int tab_id = SessionTabHelper::IdForTab(web_contents); RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoConnectRouteByRouteId, - base::Unretained(this), source_id, route_id, - origin.is_empty() ? "" : origin.spec(), tab_id, - callbacks, timeout, incognito)); + base::Unretained(this), source_id, route_id, origin, + tab_id, callbacks, timeout, incognito)); } void MediaRouterMojoImpl::TerminateRoute(const MediaRoute::Id& route_id) { @@ -459,7 +417,8 @@ // |observer| can be immediately notified with an empty list. sinks_query->observers.AddObserver(observer); if (availability_ == mojom::MediaRouter::SinkAvailability::UNAVAILABLE) { - observer->OnSinksUpdated(std::vector<MediaSink>(), std::vector<GURL>()); + observer->OnSinksUpdated(std::vector<MediaSink>(), + std::vector<url::Origin>()); } else { // Need to call MRPM to start observing sinks if the query is new. if (new_query) { @@ -602,7 +561,7 @@ void MediaRouterMojoImpl::DoCreateRoute( const MediaSource::Id& source_id, const MediaSink::Id& sink_id, - const std::string& origin, + const url::Origin& origin, int tab_id, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout, @@ -610,7 +569,6 @@ std::string presentation_id = MediaRouterBase::CreatePresentationId(); DVLOG_WITH_INSTANCE(1) << "DoCreateRoute " << source_id << "=>" << sink_id << ", presentation ID: " << presentation_id; - media_route_provider_->CreateRoute( source_id, sink_id, presentation_id, origin, tab_id, timeout, incognito, base::Bind(&MediaRouterMojoImpl::RouteResponseReceived, @@ -621,7 +579,7 @@ void MediaRouterMojoImpl::DoJoinRoute( const MediaSource::Id& source_id, const std::string& presentation_id, - const std::string& origin, + const url::Origin& origin, int tab_id, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout, @@ -639,7 +597,7 @@ void MediaRouterMojoImpl::DoConnectRouteByRouteId( const MediaSource::Id& source_id, const MediaRoute::Id& route_id, - const std::string& origin, + const url::Origin& origin, int tab_id, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout,
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl.h b/chrome/browser/media/router/mojo/media_router_mojo_impl.h index 4ee4caf..0b38e048 100644 --- a/chrome/browser/media/router/mojo/media_router_mojo_impl.h +++ b/chrome/browser/media/router/mojo/media_router_mojo_impl.h
@@ -69,14 +69,14 @@ // enqueued for later use if the extension is temporarily suspended. void CreateRoute(const MediaSource::Id& source_id, const MediaSink::Id& sink_id, - const GURL& origin, + const url::Origin& origin, content::WebContents* web_contents, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout, bool incognito) override; void JoinRoute(const MediaSource::Id& source_id, const std::string& presentation_id, - const GURL& origin, + const url::Origin& origin, content::WebContents* web_contents, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout, @@ -84,7 +84,7 @@ void ConnectRouteByRouteId( const MediaSource::Id& source, const MediaRoute::Id& route_id, - const GURL& origin, + const url::Origin& origin, content::WebContents* web_contents, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout, @@ -175,7 +175,7 @@ // Cached list of sinks for the query, if |has_cached_result| is true. // Empty otherwise. std::vector<MediaSink> cached_sink_list; - std::vector<GURL> origins; + std::vector<url::Origin> origins; base::ObserverList<MediaSinksObserver> observers; private: @@ -234,14 +234,14 @@ // These calls invoke methods in the component extension via Mojo. void DoCreateRoute(const MediaSource::Id& source_id, const MediaSink::Id& sink_id, - const std::string& origin, + const url::Origin& origin, int tab_id, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout, bool incognito); void DoJoinRoute(const MediaSource::Id& source_id, const std::string& presentation_id, - const std::string& origin, + const url::Origin& origin, int tab_id, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout, @@ -249,7 +249,7 @@ void DoConnectRouteByRouteId( const MediaSource::Id& source_id, const MediaRoute::Id& route_id, - const std::string& origin, + const url::Origin& origin, int tab_id, const std::vector<MediaRouteResponseCallback>& callbacks, base::TimeDelta timeout, @@ -286,7 +286,7 @@ void OnIssue(const IssueInfo& issue) override; void OnSinksReceived(const std::string& media_source, std::vector<mojom::MediaSinkPtr> sinks, - const std::vector<std::string>& origins) override; + const std::vector<url::Origin>& origins) override; void OnRoutesUpdated( std::vector<mojom::MediaRoutePtr> routes, const std::string& media_source,
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl_unittest.cc b/chrome/browser/media/router/mojo/media_router_mojo_impl_unittest.cc index e360552..70df1a6 100644 --- a/chrome/browser/media/router/mojo/media_router_mojo_impl_unittest.cc +++ b/chrome/browser/media/router/mojo/media_router_mojo_impl_unittest.cc
@@ -195,10 +195,11 @@ // a limitation with GMock::Invoke that prevents it from using move-only types // in runnable parameter lists. EXPECT_CALL(mock_media_route_provider_, - CreateRoute(kSource, kSinkId, _, kOrigin, kInvalidTabId, _, _, _)) + CreateRoute(kSource, kSinkId, _, url::Origin(GURL(kOrigin)), + kInvalidTabId, _, _, _)) .WillOnce(Invoke( [](const std::string& source, const std::string& sink, - const std::string& presentation_id, const std::string& origin, + const std::string& presentation_id, const url::Origin& origin, int tab_id, base::TimeDelta timeout, bool incognito, const mojom::MediaRouteProvider::CreateRouteCallback& cb) { cb.Run(CreateMojoRoute(), std::string(), @@ -213,9 +214,10 @@ std::vector<MediaRouteResponseCallback> route_response_callbacks; route_response_callbacks.push_back(base::Bind( &RouteResponseCallbackHandler::Invoke, base::Unretained(&handler))); - router()->CreateRoute( - kSource, kSinkId, GURL(kOrigin), nullptr, route_response_callbacks, - base::TimeDelta::FromMilliseconds(kTimeoutMillis), false); + router()->CreateRoute(kSource, kSinkId, url::Origin(GURL(kOrigin)), nullptr, + route_response_callbacks, + base::TimeDelta::FromMilliseconds(kTimeoutMillis), + false); run_loop.Run(); ExpectResultBucketCount("CreateRoute", RouteRequestResult::ResultCode::OK, 1); } @@ -230,10 +232,11 @@ // a limitation with GMock::Invoke that prevents it from using move-only types // in runnable parameter lists. EXPECT_CALL(mock_media_route_provider_, - CreateRoute(kSource, kSinkId, _, kOrigin, kInvalidTabId, _, _, _)) + CreateRoute(kSource, kSinkId, _, url::Origin(GURL(kOrigin)), + kInvalidTabId, _, _, _)) .WillOnce(Invoke( [](const std::string& source, const std::string& sink, - const std::string& presentation_id, const std::string& origin, + const std::string& presentation_id, const url::Origin& origin, int tab_id, base::TimeDelta timeout, bool incognito, const mojom::MediaRouteProvider::CreateRouteCallback& cb) { mojom::MediaRoutePtr route = CreateMojoRoute(); @@ -252,9 +255,10 @@ std::vector<MediaRouteResponseCallback> route_response_callbacks; route_response_callbacks.push_back(base::Bind( &RouteResponseCallbackHandler::Invoke, base::Unretained(&handler))); - router()->CreateRoute( - kSource, kSinkId, GURL(kOrigin), nullptr, route_response_callbacks, - base::TimeDelta::FromMilliseconds(kTimeoutMillis), true); + router()->CreateRoute(kSource, kSinkId, url::Origin(GURL(kOrigin)), nullptr, + route_response_callbacks, + base::TimeDelta::FromMilliseconds(kTimeoutMillis), + true); run_loop.Run(); ExpectResultBucketCount("CreateRoute", RouteRequestResult::ResultCode::OK, 1); } @@ -262,11 +266,12 @@ TEST_F(MediaRouterMojoImplTest, CreateRouteFails) { EXPECT_CALL( mock_media_route_provider_, - CreateRoute(kSource, kSinkId, _, kOrigin, kInvalidTabId, + CreateRoute(kSource, kSinkId, _, url::Origin(GURL(kOrigin)), + kInvalidTabId, base::TimeDelta::FromMilliseconds(kTimeoutMillis), _, _)) .WillOnce(Invoke( [](const std::string& source, const std::string& sink, - const std::string& presentation_id, const std::string& origin, + const std::string& presentation_id, const url::Origin& origin, int tab_id, base::TimeDelta timeout, bool incognito, const mojom::MediaRouteProvider::CreateRouteCallback& cb) { cb.Run(mojom::MediaRoutePtr(), std::string(kError), @@ -281,22 +286,24 @@ std::vector<MediaRouteResponseCallback> route_response_callbacks; route_response_callbacks.push_back(base::Bind( &RouteResponseCallbackHandler::Invoke, base::Unretained(&handler))); - router()->CreateRoute( - kSource, kSinkId, GURL(kOrigin), nullptr, route_response_callbacks, - base::TimeDelta::FromMilliseconds(kTimeoutMillis), false); + router()->CreateRoute(kSource, kSinkId, url::Origin(GURL(kOrigin)), nullptr, + route_response_callbacks, + base::TimeDelta::FromMilliseconds(kTimeoutMillis), + false); run_loop.Run(); ExpectResultBucketCount("CreateRoute", RouteRequestResult::ResultCode::TIMED_OUT, 1); } TEST_F(MediaRouterMojoImplTest, CreateRouteIncognitoMismatchFails) { - EXPECT_CALL(mock_media_route_provider_, - CreateRoute(kSource, kSinkId, _, kOrigin, kInvalidTabId, - base::TimeDelta::FromMilliseconds(kTimeoutMillis), - true, _)) + EXPECT_CALL( + mock_media_route_provider_, + CreateRoute(kSource, kSinkId, _, url::Origin(GURL(kOrigin)), + kInvalidTabId, + base::TimeDelta::FromMilliseconds(kTimeoutMillis), true, _)) .WillOnce(Invoke( [](const std::string& source, const std::string& sink, - const std::string& presentation_id, const std::string& origin, + const std::string& presentation_id, const url::Origin& origin, int tab_id, base::TimeDelta timeout, bool incognito, const mojom::MediaRouteProvider::CreateRouteCallback& cb) { cb.Run(CreateMojoRoute(), std::string(), @@ -312,9 +319,10 @@ std::vector<MediaRouteResponseCallback> route_response_callbacks; route_response_callbacks.push_back(base::Bind( &RouteResponseCallbackHandler::Invoke, base::Unretained(&handler))); - router()->CreateRoute( - kSource, kSinkId, GURL(kOrigin), nullptr, route_response_callbacks, - base::TimeDelta::FromMilliseconds(kTimeoutMillis), true); + router()->CreateRoute(kSource, kSinkId, url::Origin(GURL(kOrigin)), nullptr, + route_response_callbacks, + base::TimeDelta::FromMilliseconds(kTimeoutMillis), + true); run_loop.Run(); ExpectResultBucketCount( "CreateRoute", RouteRequestResult::ResultCode::INCOGNITO_MISMATCH, 1); @@ -324,13 +332,14 @@ mojom::MediaRoutePtr route = CreateMojoRoute(); route->is_incognito = true; - EXPECT_CALL(mock_media_route_provider_, - CreateRoute(kSource, kSinkId, _, kOrigin, kInvalidTabId, - base::TimeDelta::FromMilliseconds(kTimeoutMillis), - true, _)) + EXPECT_CALL( + mock_media_route_provider_, + CreateRoute(kSource, kSinkId, _, url::Origin(GURL(kOrigin)), + kInvalidTabId, + base::TimeDelta::FromMilliseconds(kTimeoutMillis), true, _)) .WillOnce(Invoke( [](const std::string& source, const std::string& sink, - const std::string& presentation_id, const std::string& origin, + const std::string& presentation_id, const url::Origin& origin, int tab_id, base::TimeDelta timeout, bool incognito, const mojom::MediaRouteProvider::CreateRouteCallback& cb) { mojom::MediaRoutePtr route = CreateMojoRoute(); @@ -339,7 +348,7 @@ mojom::RouteRequestResultCode::OK); })); base::RunLoop run_loop; - router()->CreateRoute(kSource, kSinkId, GURL(kOrigin), nullptr, + router()->CreateRoute(kSource, kSinkId, url::Origin(GURL(kOrigin)), nullptr, std::vector<MediaRouteResponseCallback>(), base::TimeDelta::FromMilliseconds(kTimeoutMillis), true); @@ -383,11 +392,12 @@ // in runnable parameter lists. EXPECT_CALL( mock_media_route_provider_, - JoinRoute(kSource, kPresentationId, kOrigin, kInvalidTabId, + JoinRoute(kSource, kPresentationId, url::Origin(GURL(kOrigin)), + kInvalidTabId, base::TimeDelta::FromMilliseconds(kTimeoutMillis), _, _)) .WillOnce(Invoke([&route]( const std::string& source, const std::string& presentation_id, - const std::string& origin, int tab_id, base::TimeDelta timeout, + const url::Origin& origin, int tab_id, base::TimeDelta timeout, bool incognito, const mojom::MediaRouteProvider::JoinRouteCallback& cb) { cb.Run(std::move(route), std::string(), @@ -402,8 +412,8 @@ std::vector<MediaRouteResponseCallback> route_response_callbacks; route_response_callbacks.push_back(base::Bind( &RouteResponseCallbackHandler::Invoke, base::Unretained(&handler))); - router()->JoinRoute(kSource, kPresentationId, GURL(kOrigin), nullptr, - route_response_callbacks, + router()->JoinRoute(kSource, kPresentationId, url::Origin(GURL(kOrigin)), + nullptr, route_response_callbacks, base::TimeDelta::FromMilliseconds(kTimeoutMillis), false); run_loop.Run(); ExpectResultBucketCount("JoinRoute", RouteRequestResult::ResultCode::OK, 1); @@ -418,8 +428,8 @@ std::vector<MediaRouteResponseCallback> route_response_callbacks; route_response_callbacks.push_back(base::Bind( &RouteResponseCallbackHandler::Invoke, base::Unretained(&handler))); - router()->JoinRoute(kSource, kPresentationId, GURL(kOrigin), nullptr, - route_response_callbacks, + router()->JoinRoute(kSource, kPresentationId, url::Origin(GURL(kOrigin)), + nullptr, route_response_callbacks, base::TimeDelta::FromMilliseconds(kTimeoutMillis), false); run_loop.Run(); ExpectResultBucketCount("JoinRoute", @@ -437,11 +447,12 @@ EXPECT_CALL( mock_media_route_provider_, - JoinRoute(kSource, kPresentationId, kOrigin, kInvalidTabId, + JoinRoute(kSource, kPresentationId, url::Origin(GURL(kOrigin)), + kInvalidTabId, base::TimeDelta::FromMilliseconds(kTimeoutMillis), _, _)) .WillOnce(Invoke( [](const std::string& source, const std::string& presentation_id, - const std::string& origin, int tab_id, base::TimeDelta timeout, + const url::Origin& origin, int tab_id, base::TimeDelta timeout, bool incognito, const mojom::MediaRouteProvider::JoinRouteCallback& cb) { cb.Run(mojom::MediaRoutePtr(), std::string(kError), @@ -456,8 +467,8 @@ std::vector<MediaRouteResponseCallback> route_response_callbacks; route_response_callbacks.push_back(base::Bind( &RouteResponseCallbackHandler::Invoke, base::Unretained(&handler))); - router()->JoinRoute(kSource, kPresentationId, GURL(kOrigin), nullptr, - route_response_callbacks, + router()->JoinRoute(kSource, kPresentationId, url::Origin(GURL(kOrigin)), + nullptr, route_response_callbacks, base::TimeDelta::FromMilliseconds(kTimeoutMillis), false); run_loop.Run(); ExpectResultBucketCount("JoinRoute", @@ -480,11 +491,12 @@ // in runnable parameter lists. EXPECT_CALL( mock_media_route_provider_, - JoinRoute(kSource, kPresentationId, kOrigin, kInvalidTabId, + JoinRoute(kSource, kPresentationId, url::Origin(GURL(kOrigin)), + kInvalidTabId, base::TimeDelta::FromMilliseconds(kTimeoutMillis), true, _)) .WillOnce(Invoke([&route]( const std::string& source, const std::string& presentation_id, - const std::string& origin, int tab_id, base::TimeDelta timeout, + const url::Origin& origin, int tab_id, base::TimeDelta timeout, bool incognito, const mojom::MediaRouteProvider::JoinRouteCallback& cb) { cb.Run(std::move(route), std::string(), @@ -500,8 +512,8 @@ std::vector<MediaRouteResponseCallback> route_response_callbacks; route_response_callbacks.push_back(base::Bind( &RouteResponseCallbackHandler::Invoke, base::Unretained(&handler))); - router()->JoinRoute(kSource, kPresentationId, GURL(kOrigin), nullptr, - route_response_callbacks, + router()->JoinRoute(kSource, kPresentationId, url::Origin(GURL(kOrigin)), + nullptr, route_response_callbacks, base::TimeDelta::FromMilliseconds(kTimeoutMillis), true); run_loop.Run(); ExpectResultBucketCount( @@ -520,12 +532,12 @@ // in runnable parameter lists. EXPECT_CALL( mock_media_route_provider_, - ConnectRouteByRouteId(kSource, kRouteId, _, kOrigin, kInvalidTabId, - base::TimeDelta::FromMilliseconds(kTimeoutMillis), - false, _)) + ConnectRouteByRouteId( + kSource, kRouteId, _, url::Origin(GURL(kOrigin)), kInvalidTabId, + base::TimeDelta::FromMilliseconds(kTimeoutMillis), false, _)) .WillOnce(Invoke([&route]( const std::string& source, const std::string& route_id, - const std::string& presentation_id, const std::string& origin, + const std::string& presentation_id, const url::Origin& origin, int tab_id, base::TimeDelta timeout, bool incognito, const mojom::MediaRouteProvider::JoinRouteCallback& cb) { cb.Run(std::move(route), std::string(), @@ -541,7 +553,8 @@ route_response_callbacks.push_back(base::Bind( &RouteResponseCallbackHandler::Invoke, base::Unretained(&handler))); router()->ConnectRouteByRouteId( - kSource, kRouteId, GURL(kOrigin), nullptr, route_response_callbacks, + kSource, kRouteId, url::Origin(GURL(kOrigin)), nullptr, + route_response_callbacks, base::TimeDelta::FromMilliseconds(kTimeoutMillis), false); run_loop.Run(); ExpectResultBucketCount("JoinRoute", RouteRequestResult::ResultCode::OK, 1); @@ -550,12 +563,12 @@ TEST_F(MediaRouterMojoImplTest, ConnectRouteByRouteIdFails) { EXPECT_CALL( mock_media_route_provider_, - ConnectRouteByRouteId(kSource, kRouteId, _, kOrigin, kInvalidTabId, - base::TimeDelta::FromMilliseconds(kTimeoutMillis), - true, _)) + ConnectRouteByRouteId( + kSource, kRouteId, _, url::Origin(GURL(kOrigin)), kInvalidTabId, + base::TimeDelta::FromMilliseconds(kTimeoutMillis), true, _)) .WillOnce(Invoke( [](const std::string& source, const std::string& route_id, - const std::string& presentation_id, const std::string& origin, + const std::string& presentation_id, const url::Origin& origin, int tab_id, base::TimeDelta timeout, bool incognito, const mojom::MediaRouteProvider::JoinRouteCallback& cb) { cb.Run(mojom::MediaRoutePtr(), std::string(kError), @@ -571,7 +584,8 @@ route_response_callbacks.push_back(base::Bind( &RouteResponseCallbackHandler::Invoke, base::Unretained(&handler))); router()->ConnectRouteByRouteId( - kSource, kRouteId, GURL(kOrigin), nullptr, route_response_callbacks, + kSource, kRouteId, url::Origin(GURL(kOrigin)), nullptr, + route_response_callbacks, base::TimeDelta::FromMilliseconds(kTimeoutMillis), true); run_loop.Run(); ExpectResultBucketCount("JoinRoute", @@ -586,12 +600,12 @@ // in runnable parameter lists. EXPECT_CALL( mock_media_route_provider_, - ConnectRouteByRouteId(kSource, kRouteId, _, kOrigin, kInvalidTabId, - base::TimeDelta::FromMilliseconds(kTimeoutMillis), - true, _)) + ConnectRouteByRouteId( + kSource, kRouteId, _, url::Origin(GURL(kOrigin)), kInvalidTabId, + base::TimeDelta::FromMilliseconds(kTimeoutMillis), true, _)) .WillOnce(Invoke([&route]( const std::string& source, const std::string& route_id, - const std::string& presentation_id, const std::string& origin, + const std::string& presentation_id, const url::Origin& origin, int tab_id, base::TimeDelta timeout, bool incognito, const mojom::MediaRouteProvider::JoinRouteCallback& cb) { cb.Run(std::move(route), std::string(), @@ -608,7 +622,8 @@ route_response_callbacks.push_back(base::Bind( &RouteResponseCallbackHandler::Invoke, base::Unretained(&handler))); router()->ConnectRouteByRouteId( - kSource, kRouteId, GURL(kOrigin), nullptr, route_response_callbacks, + kSource, kRouteId, url::Origin(GURL(kOrigin)), nullptr, + route_response_callbacks, base::TimeDelta::FromMilliseconds(kTimeoutMillis), true); run_loop.Run(); ExpectResultBucketCount( @@ -696,7 +711,6 @@ router()->OnSinkAvailabilityUpdated( mojom::MediaRouter::SinkAvailability::AVAILABLE); MediaSource media_source(kSource); - GURL origin("https://google.com"); // These should only be called once even if there is more than one observer // for a given source. @@ -704,13 +718,16 @@ EXPECT_CALL(mock_media_route_provider_, StartObservingMediaSinks(kSource2)); std::unique_ptr<MockMediaSinksObserver> sinks_observer( - new MockMediaSinksObserver(router(), media_source, origin)); + new MockMediaSinksObserver(router(), media_source, + url::Origin(GURL(kOrigin)))); EXPECT_TRUE(sinks_observer->Init()); std::unique_ptr<MockMediaSinksObserver> extra_sinks_observer( - new MockMediaSinksObserver(router(), media_source, origin)); + new MockMediaSinksObserver(router(), media_source, + url::Origin(GURL(kOrigin)))); EXPECT_TRUE(extra_sinks_observer->Init()); std::unique_ptr<MockMediaSinksObserver> unrelated_sinks_observer( - new MockMediaSinksObserver(router(), MediaSource(kSource2), origin)); + new MockMediaSinksObserver(router(), MediaSource(kSource2), + url::Origin(GURL(kOrigin)))); EXPECT_TRUE(unrelated_sinks_observer->Init()); ProcessEventLoop(); @@ -739,14 +756,15 @@ .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); media_router_proxy_->OnSinksReceived( media_source.id(), std::move(mojo_sinks), - std::vector<std::string>(1, origin.spec())); + std::vector<url::Origin>(1, url::Origin(GURL(kOrigin)))); run_loop.Run(); // Since the MediaRouterMojoImpl has already received results for // |media_source|, return cached results to observers that are subsequently // registered. std::unique_ptr<MockMediaSinksObserver> cached_sinks_observer( - new MockMediaSinksObserver(router(), media_source, origin)); + new MockMediaSinksObserver(router(), media_source, + url::Origin(GURL(kOrigin)))); EXPECT_CALL(*cached_sinks_observer, OnSinksReceived(SequenceEquals(expected_sinks))); EXPECT_TRUE(cached_sinks_observer->Init()); @@ -754,7 +772,7 @@ // Different origin from cached result. Empty list will be returned. std::unique_ptr<MockMediaSinksObserver> cached_sinks_observer2( new MockMediaSinksObserver(router(), media_source, - GURL("https://youtube.com"))); + url::Origin(GURL("https://youtube.com")))); EXPECT_CALL(*cached_sinks_observer2, OnSinksReceived(IsEmpty())); EXPECT_TRUE(cached_sinks_observer2->Init()); @@ -772,19 +790,20 @@ TEST_F(MediaRouterMojoImplTest, RegisterMediaSinksObserverWithAvailabilityChange) { - GURL origin("https://google.com"); // When availability is UNAVAILABLE, no calls should be made to MRPM. router()->OnSinkAvailabilityUpdated( mojom::MediaRouter::SinkAvailability::UNAVAILABLE); MediaSource media_source(kSource); std::unique_ptr<MockMediaSinksObserver> sinks_observer( - new MockMediaSinksObserver(router(), media_source, origin)); + new MockMediaSinksObserver(router(), media_source, + url::Origin(GURL(kOrigin)))); EXPECT_CALL(*sinks_observer, OnSinksReceived(IsEmpty())); EXPECT_TRUE(sinks_observer->Init()); MediaSource media_source2(kSource2); std::unique_ptr<MockMediaSinksObserver> sinks_observer2( - new MockMediaSinksObserver(router(), media_source2, origin)); + new MockMediaSinksObserver(router(), media_source2, + url::Origin(GURL(kOrigin)))); EXPECT_CALL(*sinks_observer2, OnSinksReceived(IsEmpty())); EXPECT_TRUE(sinks_observer2->Init()); EXPECT_CALL(mock_media_route_provider_, StartObservingMediaSinks(kSource))
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_test.h b/chrome/browser/media/router/mojo/media_router_mojo_test.h index 72609c8..b978c6d 100644 --- a/chrome/browser/media/router/mojo/media_router_mojo_test.h +++ b/chrome/browser/media/router/mojo/media_router_mojo_test.h
@@ -34,7 +34,7 @@ void(const std::string& source_urn, const std::string& sink_id, const std::string& presentation_id, - const std::string& origin, + const url::Origin& origin, int tab_id, base::TimeDelta timeout, bool incognito, @@ -42,7 +42,7 @@ MOCK_METHOD7(JoinRoute, void(const std::string& source_urn, const std::string& presentation_id, - const std::string& origin, + const url::Origin& origin, int tab_id, base::TimeDelta timeout, bool incognito, @@ -51,7 +51,7 @@ void(const std::string& source_urn, const std::string& route_id, const std::string& presentation_id, - const std::string& origin, + const url::Origin& origin, int tab_id, base::TimeDelta timeout, bool incognito,
diff --git a/chrome/browser/media/router/presentation_media_sinks_observer.cc b/chrome/browser/media/router/presentation_media_sinks_observer.cc index 5bc1429..5a8d6281 100644 --- a/chrome/browser/media/router/presentation_media_sinks_observer.cc +++ b/chrome/browser/media/router/presentation_media_sinks_observer.cc
@@ -14,7 +14,7 @@ MediaRouter* router, content::PresentationScreenAvailabilityListener* listener, const MediaSource& source, - const GURL& origin) + const url::Origin& origin) : MediaSinksObserver(router, source, origin), listener_(listener), previous_availablity_(UNKNOWN) {
diff --git a/chrome/browser/media/router/presentation_media_sinks_observer.h b/chrome/browser/media/router/presentation_media_sinks_observer.h index ce13d9b..b8960027 100644 --- a/chrome/browser/media/router/presentation_media_sinks_observer.h +++ b/chrome/browser/media/router/presentation_media_sinks_observer.h
@@ -35,7 +35,7 @@ MediaRouter* router, content::PresentationScreenAvailabilityListener* listener, const MediaSource& source, - const GURL& origin); + const url::Origin& origin); ~PresentationMediaSinksObserver() override; // MediaSinksObserver implementation.
diff --git a/chrome/browser/media/router/presentation_media_sinks_observer_unittest.cc b/chrome/browser/media/router/presentation_media_sinks_observer_unittest.cc index 96166a8..7e9cc6b 100644 --- a/chrome/browser/media/router/presentation_media_sinks_observer_unittest.cc +++ b/chrome/browser/media/router/presentation_media_sinks_observer_unittest.cc
@@ -20,6 +20,10 @@ namespace media_router { +namespace { +constexpr char kOrigin[] = "https://google.com"; +} // namespace + class PresentationMediaSinksObserverTest : public ::testing::Test { public: PresentationMediaSinksObserverTest() @@ -31,7 +35,7 @@ observer_.reset(new PresentationMediaSinksObserver( &router_, &listener_, MediaSourceForPresentationUrl( GURL("http://example.com/presentation.html")), - GURL("https://google.com"))); + url::Origin(GURL(kOrigin)))); EXPECT_TRUE(observer_->Init()); }
diff --git a/chrome/browser/media/router/presentation_request.cc b/chrome/browser/media/router/presentation_request.cc index 89f7b4fb..3952d0a 100644 --- a/chrome/browser/media/router/presentation_request.cc +++ b/chrome/browser/media/router/presentation_request.cc
@@ -11,10 +11,10 @@ PresentationRequest::PresentationRequest( const RenderFrameHostId& render_frame_host_id, const std::vector<GURL>& presentation_urls, - const GURL& frame_url) + const url::Origin& frame_origin) : render_frame_host_id_(render_frame_host_id), presentation_urls_(presentation_urls), - frame_url_(frame_url) { + frame_origin_(frame_origin) { DCHECK(!presentation_urls_.empty()); } @@ -26,7 +26,8 @@ bool PresentationRequest::Equals(const PresentationRequest& other) const { return render_frame_host_id_ == other.render_frame_host_id_ && presentation_urls_ == other.presentation_urls_ && - frame_url_ == other.frame_url_; + ((frame_origin_.unique() && other.frame_origin_.unique()) || + (frame_origin_ == other.frame_origin_)); } std::vector<MediaSource> PresentationRequest::GetMediaSources() const {
diff --git a/chrome/browser/media/router/presentation_request.h b/chrome/browser/media/router/presentation_request.h index 1879ec1..e305673 100644 --- a/chrome/browser/media/router/presentation_request.h +++ b/chrome/browser/media/router/presentation_request.h
@@ -10,7 +10,7 @@ #include "chrome/browser/media/router/media_source.h" #include "chrome/browser/media/router/render_frame_host_id.h" -#include "url/gurl.h" +#include "url/origin.h" namespace media_router { @@ -20,7 +20,7 @@ public: PresentationRequest(const RenderFrameHostId& render_frame_host_id, const std::vector<GURL>& presentation_urls, - const GURL& frame_url); + const url::Origin& frame_origin); PresentationRequest(const PresentationRequest& other); ~PresentationRequest(); @@ -35,7 +35,7 @@ const std::vector<GURL>& presentation_urls() const { return presentation_urls_; } - const GURL& frame_url() const { return frame_url_; } + const url::Origin& frame_origin() const { return frame_origin_; } private: // ID of RenderFrameHost that initiated the request. @@ -44,10 +44,8 @@ // URLs of presentation. const std::vector<GURL> presentation_urls_; - // URL of frame from which the request was initiated. - // TODO(crbug.com/632623): Convert this to url::Origin as only the origin or - // hostname is used. - const GURL frame_url_; + // Origin of frame from which the request was initiated. + const url::Origin frame_origin_; }; } // namespace media_router
diff --git a/chrome/browser/media/router/presentation_request_unittest.cc b/chrome/browser/media/router/presentation_request_unittest.cc index 165b5d0..8144d73 100644 --- a/chrome/browser/media/router/presentation_request_unittest.cc +++ b/chrome/browser/media/router/presentation_request_unittest.cc
@@ -8,17 +8,17 @@ namespace media_router { TEST(PresentationRequestTest, Equals) { - GURL frame_url("http://www.site.com/"); + url::Origin frame_origin(GURL("http://www.site.com/")); std::vector<GURL> presentation_urls = { GURL("http://www.example.com/presentation.html"), GURL("http://www.example.net/alternate.html")}; PresentationRequest request1(RenderFrameHostId(1, 2), presentation_urls, - frame_url); + frame_origin); // Frame IDs are different. PresentationRequest request2(RenderFrameHostId(3, 4), presentation_urls, - frame_url); + frame_origin); EXPECT_FALSE(request1.Equals(request2)); // Presentation URLs are different. @@ -26,19 +26,19 @@ RenderFrameHostId(1, 2), {GURL("http://www.example.net/presentation.html"), GURL("http://www.example.com/presentation.html")}, - frame_url); + frame_origin); EXPECT_FALSE(request1.Equals(request3)); // Frame URLs are different. PresentationRequest request4(RenderFrameHostId(1, 2), presentation_urls, - GURL("http://www.site.net/")); + url::Origin(GURL("http://www.site.net/"))); EXPECT_FALSE(request1.Equals(request4)); PresentationRequest request5( RenderFrameHostId(1, 2), {GURL("http://www.example.com/presentation.html"), GURL("http://www.example.net/alternate.html")}, - GURL("http://www.site.com/")); + url::Origin(GURL("http://www.site.com/"))); EXPECT_TRUE(request1.Equals(request5)); }
diff --git a/chrome/browser/media/router/presentation_service_delegate_impl.cc b/chrome/browser/media/router/presentation_service_delegate_impl.cc index 83e6e78..9f2d182 100644 --- a/chrome/browser/media/router/presentation_service_delegate_impl.cc +++ b/chrome/browser/media/router/presentation_service_delegate_impl.cc
@@ -61,14 +61,12 @@ // Gets the last committed URL for the render frame specified by // |render_frame_host_id|. -GURL GetLastCommittedURLForFrame(RenderFrameHostId render_frame_host_id) { +url::Origin GetLastCommittedURLForFrame( + RenderFrameHostId render_frame_host_id) { RenderFrameHost* render_frame_host = RenderFrameHost::FromID( render_frame_host_id.first, render_frame_host_id.second); - if (!render_frame_host) - return GURL(); - - // TODO(crbug.com/632623): Use url::Origin in place of GURL for origins - return render_frame_host->GetLastCommittedOrigin().GetURL(); + DCHECK(render_frame_host); + return render_frame_host->GetLastCommittedOrigin(); } // Observes messages originating from the MediaSink connected to a MediaRoute @@ -233,7 +231,7 @@ sinks_observer.reset(new PresentationMediaSinksObserver( router_, listener, source, - GetLastCommittedURLForFrame(render_frame_host_id_).GetOrigin())); + GetLastCommittedURLForFrame(render_frame_host_id_))); if (!sinks_observer->Init()) { url_to_sinks_observer_.erase(source.id()); @@ -623,9 +621,10 @@ ClearDefaultPresentationRequest(); } else { DCHECK(!callback.is_null()); - GURL frame_url(GetLastCommittedURLForFrame(render_frame_host_id)); + const auto& frame_origin = + GetLastCommittedURLForFrame(render_frame_host_id); PresentationRequest request(render_frame_host_id, default_presentation_urls, - frame_url); + frame_origin); default_presentation_started_callback_ = callback; SetDefaultPresentationRequest(request); } @@ -878,8 +877,8 @@ return; } - const url::Origin& origin = url::Origin(GetLastCommittedURLForFrame( - RenderFrameHostId(render_process_id, render_frame_id))); + const url::Origin& origin = GetLastCommittedURLForFrame( + RenderFrameHostId(render_process_id, render_frame_id)); #if !defined(OS_ANDROID) if (IsAutoJoinPresentationId(presentation_id) && @@ -900,7 +899,7 @@ weak_factory_.GetWeakPtr(), render_process_id, render_frame_id, presentation_url, presentation_id, success_cb, error_cb)); router_->JoinRoute(MediaSourceForPresentationUrl(presentation_url).id(), - presentation_id, origin.GetURL(), web_contents_, + presentation_id, origin, web_contents_, route_response_callbacks, base::TimeDelta(), incognito); }
diff --git a/chrome/browser/media/router/presentation_service_delegate_impl_unittest.cc b/chrome/browser/media/router/presentation_service_delegate_impl_unittest.cc index 85b65c41..edfdc20 100644 --- a/chrome/browser/media/router/presentation_service_delegate_impl_unittest.cc +++ b/chrome/browser/media/router/presentation_service_delegate_impl_unittest.cc
@@ -152,8 +152,9 @@ EXPECT_TRUE(Mock::VerifyAndClearExpectations(this)); // Should not trigger callback since request doesn't match. - PresentationRequest different_request( - RenderFrameHostId(100, 200), {presentation_url2_}, GURL(kFrameUrl)); + PresentationRequest different_request(RenderFrameHostId(100, 200), + {presentation_url2_}, + url::Origin(GURL(kFrameUrl))); MediaRoute* media_route = new MediaRoute("differentRouteId", source2_, "mediaSinkId", "", true, "", true); media_route->set_incognito(incognito); @@ -322,7 +323,7 @@ EXPECT_EQ(presentation_url1_, request1.presentation_urls()[0]); EXPECT_EQ(RenderFrameHostId(main_frame_process_id_, main_frame_routing_id_), request1.render_frame_host_id()); - EXPECT_EQ(frame_url, request1.frame_url()); + EXPECT_EQ(url::Origin(frame_url), request1.frame_origin()); // Set to a new default presentation URL std::vector<GURL> new_urls = {presentation_url2_}; @@ -334,7 +335,7 @@ EXPECT_EQ(presentation_url2_, request2.presentation_urls()[0]); EXPECT_EQ(RenderFrameHostId(main_frame_process_id_, main_frame_routing_id_), request2.render_frame_host_id()); - EXPECT_EQ(frame_url, request2.frame_url()); + EXPECT_EQ(url::Origin(frame_url), request2.frame_origin()); // Remove default presentation URL. delegate_impl_->SetDefaultPresentationUrls(main_frame_process_id_, @@ -368,7 +369,7 @@ std::vector<GURL> request1_urls = {presentation_url1_}; PresentationRequest observed_request1( RenderFrameHostId(main_frame_process_id_, main_frame_routing_id_), - request1_urls, frame_url); + request1_urls, url::Origin(frame_url)); EXPECT_CALL(observer, OnDefaultPresentationChanged(Equals(observed_request1))) .Times(1); delegate_impl_->SetDefaultPresentationUrls( @@ -384,7 +385,7 @@ std::vector<GURL> request2_urls = {presentation_url2_}; PresentationRequest observed_request2( RenderFrameHostId(main_frame_process_id_, main_frame_routing_id_), - request2_urls, frame_url); + request2_urls, url::Origin(frame_url)); EXPECT_CALL(observer, OnDefaultPresentationChanged(Equals(observed_request2))) .Times(1); delegate_impl_->SetDefaultPresentationUrls(
diff --git a/chrome/browser/media/router/test_helper.cc b/chrome/browser/media/router/test_helper.cc index 8d38dd65..5d98680 100644 --- a/chrome/browser/media/router/test_helper.cc +++ b/chrome/browser/media/router/test_helper.cc
@@ -14,7 +14,7 @@ MockMediaSinksObserver::MockMediaSinksObserver(MediaRouter* router, const MediaSource& source, - const GURL& origin) + const url::Origin& origin) : MediaSinksObserver(router, source, origin) {} MockMediaSinksObserver::~MockMediaSinksObserver() { }
diff --git a/chrome/browser/media/router/test_helper.h b/chrome/browser/media/router/test_helper.h index 84c1001..80e2ee4 100644 --- a/chrome/browser/media/router/test_helper.h +++ b/chrome/browser/media/router/test_helper.h
@@ -62,7 +62,7 @@ public: MockMediaSinksObserver(MediaRouter* router, const MediaSource& source, - const GURL& origin); + const url::Origin& origin); ~MockMediaSinksObserver() override; MOCK_METHOD1(OnSinksReceived, void(const std::vector<MediaSink>& sinks));
diff --git a/chrome/browser/metrics/chrome_metrics_services_manager_client.cc b/chrome/browser/metrics/chrome_metrics_services_manager_client.cc index 186811f8..9d392a7c 100644 --- a/chrome/browser/metrics/chrome_metrics_services_manager_client.cc +++ b/chrome/browser/metrics/chrome_metrics_services_manager_client.cc
@@ -9,6 +9,7 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/strings/string_number_conversions.h" +#include "base/task_scheduler/post_task.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" #include "chrome/browser/metrics/chrome_metrics_service_client.h" @@ -56,18 +57,19 @@ const base::Feature kMetricsReportingFeature{"MetricsReporting", base::FEATURE_ENABLED_BY_DEFAULT}; -// Posts |GoogleUpdateSettings::StoreMetricsClientInfo| on blocking pool thread -// because it needs access to IO and cannot work from UI thread. +// Run |GoogleUpdateSettings::StoreMetricsClientInfo| asynchronously. This +// method cannot run on the UI thread because it does file I/O. void PostStoreMetricsClientInfo(const metrics::ClientInfo& client_info) { - // The message loop processes messages after the blocking pool is initialized. - // Posting a task to the message loop to post a task to the blocking pool - // ensures that the blocking pool is ready to accept tasks at that time. + // The UI thread starts running tasks after TaskScheduler is initialized. + // Posting a task to the UI thread to post a task to TaskScheduler ensures + // that TaskScheduler is ready to accept tasks at that time. content::BrowserThread::PostTask( content::BrowserThread::UI, FROM_HERE, base::Bind( [](const metrics::ClientInfo& client_info) { - content::BrowserThread::PostBlockingPoolTask( - FROM_HERE, + base::PostTaskWithTraits( + FROM_HERE, base::TaskTraits().MayBlock().WithPriority( + base::TaskPriority::BACKGROUND), base::Bind(&GoogleUpdateSettings::StoreMetricsClientInfo, client_info)); },
diff --git a/chrome/browser/notifications/non_persistent_notification_handler.cc b/chrome/browser/notifications/non_persistent_notification_handler.cc index e2c5d87..6222cd2 100644 --- a/chrome/browser/notifications/non_persistent_notification_handler.cc +++ b/chrome/browser/notifications/non_persistent_notification_handler.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/notifications/non_persistent_notification_handler.h" +#include "base/strings/nullable_string16.h" #include "chrome/browser/notifications/notification_delegate.h" #include "chrome/browser/notifications/platform_notification_service_impl.h"
diff --git a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc index b3befc0d..033f9c9 100644 --- a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc +++ b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
@@ -121,7 +121,7 @@ PrefService* pref_service) { auto provider = base::MakeUnique<DownloadSuggestionsProvider>( service, offline_page_model, download_manager, download_history, - pref_service); + pref_service, base::MakeUnique<base::DefaultClock>()); service->RegisterProvider(std::move(provider)); } #endif // OS_ANDROID
diff --git a/chrome/browser/ntp_snippets/download_suggestions_provider.cc b/chrome/browser/ntp_snippets/download_suggestions_provider.cc index c47a54d..08cb77b9 100644 --- a/chrome/browser/ntp_snippets/download_suggestions_provider.cc +++ b/chrome/browser/ntp_snippets/download_suggestions_provider.cc
@@ -16,6 +16,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_task_runner_handle.h" +#include "base/time/clock.h" #include "base/time/time.h" #include "chrome/common/chrome_features.h" #include "chrome/grit/generated_resources.h" @@ -44,23 +45,49 @@ namespace { const int kDefaultMaxSuggestionsCount = 5; +const int kDefaultMaxDownloadAgeHours = 6 * 7 * 24; // 6 weeks const char kAssetDownloadsPrefix = 'D'; const char kOfflinePageDownloadsPrefix = 'O'; +// NOTE: You must set variation param values for both features (one of them may +// be disabled in future). const char* kMaxSuggestionsCountParamName = "downloads_max_count"; +const char* kMaxDownloadAgeHoursParamName = "downloads_max_age_hours"; -bool CompareOfflinePagesMostRecentlyCreatedFirst(const OfflinePageItem& left, - const OfflinePageItem& right) { - return left.creation_time > right.creation_time; +const base::Feature& GetEnabledDownloadsFeature() { + bool assets_enabled = + base::FeatureList::IsEnabled(features::kAssetDownloadSuggestionsFeature); + DCHECK(assets_enabled || + base::FeatureList::IsEnabled( + features::kOfflinePageDownloadSuggestionsFeature)); + return assets_enabled ? features::kAssetDownloadSuggestionsFeature + : features::kOfflinePageDownloadSuggestionsFeature; } int GetMaxSuggestionsCount() { - bool assets_enabled = - base::FeatureList::IsEnabled(features::kAssetDownloadSuggestionsFeature); + // One cannot get a variation param from a disabled feature, so the enabled + // one is taken. return variations::GetVariationParamByFeatureAsInt( - assets_enabled ? features::kAssetDownloadSuggestionsFeature - : features::kOfflinePageDownloadSuggestionsFeature, - kMaxSuggestionsCountParamName, kDefaultMaxSuggestionsCount); + GetEnabledDownloadsFeature(), kMaxSuggestionsCountParamName, + kDefaultMaxSuggestionsCount); +} + +int GetMaxDownloadAgeHours() { + // One cannot get a variation param from a disabled feature, so the enabled + // one is taken. + return variations::GetVariationParamByFeatureAsInt( + GetEnabledDownloadsFeature(), kMaxDownloadAgeHoursParamName, + kDefaultMaxDownloadAgeHours); +} + +base::Time GetOfflinePagePublishedTime(const OfflinePageItem& item) { + return item.creation_time; +} + +bool CompareOfflinePagesMostRecentlyPublishedFirst( + const OfflinePageItem& left, + const OfflinePageItem& right) { + return GetOfflinePagePublishedTime(left) > GetOfflinePagePublishedTime(right); } std::string GetOfflinePagePerCategoryID(int64_t raw_offline_page_id) { @@ -91,7 +118,7 @@ return false; } -bool IsDownloadCompleted(const DownloadItem& item) { +bool IsAssetDownloadCompleted(const DownloadItem& item) { return item.GetState() == DownloadItem::DownloadState::COMPLETE && !item.GetFileExternallyRemoved(); } @@ -100,8 +127,8 @@ return item.GetStartTime(); } -bool CompareDownloadsMostRecentlyDownloadedFirst(const DownloadItem* left, - const DownloadItem* right) { +bool CompareDownloadsMostRecentlyPublishedFirst(const DownloadItem* left, + const DownloadItem* right) { return GetAssetDownloadPublishedTime(*left) > GetAssetDownloadPublishedTime(*right); } @@ -127,7 +154,8 @@ offline_pages::OfflinePageModel* offline_page_model, content::DownloadManager* download_manager, DownloadHistory* download_history, - PrefService* pref_service) + PrefService* pref_service, + std::unique_ptr<base::Clock> clock) : ContentSuggestionsProvider(observer), category_status_(CategoryStatus::AVAILABLE_LOADING), provided_category_(Category::FromKnownCategory( @@ -136,6 +164,7 @@ download_manager_(download_manager), download_history_(download_history), pref_service_(pref_service), + clock_(std::move(clock)), is_asset_downloads_initialization_complete_(false), weak_ptr_factory_(this) { observer->OnCategoryStatusChanged(this, provided_category_, category_status_); @@ -347,7 +376,7 @@ auto oldest_page_iterator = std::max_element(cached_offline_page_downloads_.begin(), cached_offline_page_downloads_.end(), - &CompareOfflinePagesMostRecentlyCreatedFirst); + &CompareOfflinePagesMostRecentlyPublishedFirst); *oldest_page_iterator = added_page; } @@ -420,7 +449,7 @@ item->RemoveObserver(this); - if (!IsDownloadCompleted(*item)) { + if (!IsAssetDownloadCompleted(*item)) { return; } // TODO(vitaliii): Implement a better way to clean up dismissed IDs (in case @@ -492,9 +521,13 @@ for (DownloadItem* item : all_downloads) { std::string within_category_id = GetAssetDownloadPerCategoryID(item->GetId()); + // TODO(vitaliii): Provide proper last access time here once it is collected + // for asset downloads. if (old_dismissed_ids.count(within_category_id)) { retained_dismissed_ids.insert(within_category_id); - } else if (IsDownloadCompleted(*item)) { + } else if (IsAssetDownloadCompleted(*item) && + !IsDownloadOutdated(GetAssetDownloadPublishedTime(*item), + base::Time())) { cached_asset_downloads_.push_back(item); // We may already observe this item and, therefore, we remove the // observer first. @@ -518,7 +551,7 @@ std::nth_element(cached_asset_downloads_.begin(), cached_asset_downloads_.begin() + max_suggestions_count, cached_asset_downloads_.end(), - &CompareDownloadsMostRecentlyDownloadedFirst); + &CompareDownloadsMostRecentlyPublishedFirst); cached_asset_downloads_.resize(max_suggestions_count); } } @@ -570,7 +603,7 @@ } else { suggestion.set_title(offline_page.title); } - suggestion.set_publish_date(offline_page.creation_time); + suggestion.set_publish_date(GetOfflinePagePublishedTime(offline_page)); suggestion.set_publisher_name(base::UTF8ToUTF16(offline_page.url.host())); auto extra = base::MakeUnique<ntp_snippets::DownloadSuggestionExtra>(); extra->is_download_asset = false; @@ -598,9 +631,20 @@ return suggestion; } +bool DownloadSuggestionsProvider::IsDownloadOutdated( + const base::Time& published_time, + const base::Time& last_visited_time) { + DCHECK(last_visited_time == base::Time() || + last_visited_time >= published_time); + const base::Time& last_interaction_time = + (last_visited_time == base::Time() ? published_time : last_visited_time); + return last_interaction_time < + clock_->Now() - base::TimeDelta::FromHours(GetMaxDownloadAgeHours()); +} + bool DownloadSuggestionsProvider::CacheAssetDownloadIfNeeded( const content::DownloadItem* item) { - if (!IsDownloadCompleted(*item)) { + if (!IsAssetDownloadCompleted(*item)) { return false; } @@ -617,9 +661,9 @@ GetMaxSuggestionsCount()); if (static_cast<int>(cached_asset_downloads_.size()) == GetMaxSuggestionsCount()) { - auto oldest = std::max_element( - cached_asset_downloads_.begin(), cached_asset_downloads_.end(), - &CompareDownloadsMostRecentlyDownloadedFirst); + auto oldest = std::max_element(cached_asset_downloads_.begin(), + cached_asset_downloads_.end(), + &CompareDownloadsMostRecentlyPublishedFirst); if (GetAssetDownloadPublishedTime(*item) <= GetAssetDownloadPublishedTime(**oldest)) { return false; @@ -706,10 +750,13 @@ for (const OfflinePageItem& item : all_download_offline_pages) { std::string id_within_category = GetOfflinePagePerCategoryID(item.offline_id); - if (!old_dismissed_ids.count(id_within_category)) { - items.push_back(&item); - } else { + if (old_dismissed_ids.count(id_within_category)) { retained_dismissed_ids.insert(id_within_category); + } else { + if (!IsDownloadOutdated(GetOfflinePagePublishedTime(item), + item.last_access_time)) { + items.push_back(&item); + } } } @@ -723,7 +770,7 @@ std::nth_element( items.begin(), items.begin() + max_suggestions_count, items.end(), [](const OfflinePageItem* left, const OfflinePageItem* right) { - return CompareOfflinePagesMostRecentlyCreatedFirst(*left, *right); + return CompareOfflinePagesMostRecentlyPublishedFirst(*left, *right); }); items.resize(max_suggestions_count); }
diff --git a/chrome/browser/ntp_snippets/download_suggestions_provider.h b/chrome/browser/ntp_snippets/download_suggestions_provider.h index 59bf356..951be12 100644 --- a/chrome/browser/ntp_snippets/download_suggestions_provider.h +++ b/chrome/browser/ntp_snippets/download_suggestions_provider.h
@@ -28,6 +28,10 @@ struct OfflinePageItem; } +namespace base { +class Clock; +} + // Provides download content suggestions from the offline pages model and the // download manager (obtaining the data through DownloadManager and each // DownloadItem). Offline page related downloads are referred to as offline page @@ -46,7 +50,8 @@ offline_pages::OfflinePageModel* offline_page_model, content::DownloadManager* download_manager, DownloadHistory* download_history, - PrefService* pref_service); + PrefService* pref_service, + std::unique_ptr<base::Clock> clock); ~DownloadSuggestionsProvider() override; // ContentSuggestionsProvider implementation. @@ -136,6 +141,11 @@ ntp_snippets::ContentSuggestion ConvertDownloadItem( const content::DownloadItem& download_item) const; + // Returns true if a download published and last visited times are considered + // too old for the download to be shown. + bool IsDownloadOutdated(const base::Time& published_time, + const base::Time& last_visited_time); + // Adds |item| to the internal asset download cache if all of the following // holds: // - the download is completed; @@ -205,8 +215,8 @@ offline_pages::OfflinePageModel* offline_page_model_; content::DownloadManager* download_manager_; DownloadHistory* download_history_; - PrefService* pref_service_; + std::unique_ptr<base::Clock> clock_; // Cached offline page downloads. If there are not enough asset downloads, all // of these could be shown (they are the most recently visited, not dismissed
diff --git a/chrome/browser/ntp_snippets/download_suggestions_provider_unittest.cc b/chrome/browser/ntp_snippets/download_suggestions_provider_unittest.cc index f63cfce..ad9a326 100644 --- a/chrome/browser/ntp_snippets/download_suggestions_provider_unittest.cc +++ b/chrome/browser/ntp_snippets/download_suggestions_provider_unittest.cc
@@ -10,6 +10,8 @@ #include "base/memory/ptr_util.h" #include "base/observer_list.h" #include "base/strings/string_number_conversions.h" +#include "base/test/simple_test_clock.h" +#include "base/time/default_clock.h" #include "chrome/browser/ntp_snippets/fake_download_item.h" #include "components/ntp_snippets/category.h" #include "components/ntp_snippets/mock_content_suggestions_provider_observer.h" @@ -88,6 +90,11 @@ namespace { +const int kDefaultMaxDownloadAgeHours = 6 * 7 * 24; + +// Tue, 31 Jan 2017 13:00:00 UTC +const base::Time now = base::Time::FromJavaTime(1485867600000); + // TODO(vitaliii): Move this and outputting functions above to common file and // replace remaining |Property(&ContentSuggestion::url, GURL("some_url"))|. // See crbug.com/655513. @@ -142,12 +149,6 @@ return result; } -OfflinePageItem CreateDummyOfflinePage(int id, base::Time time) { - OfflinePageItem item = CreateDummyOfflinePage(id); - item.creation_time = time; - return item; -} - std::unique_ptr<FakeDownloadItem> CreateDummyAssetDownload(int id) { std::unique_ptr<FakeDownloadItem> item = base::MakeUnique<FakeDownloadItem>(); item->SetId(id); @@ -268,15 +269,19 @@ EXPECT_CALL(observer_, OnSuggestionInvalidated(_, _)).Times(AnyNumber()); } - DownloadSuggestionsProvider* CreateLoadedProvider(bool show_assets, - bool show_offline_pages) { - CreateProvider(show_assets, show_offline_pages); + DownloadSuggestionsProvider* CreateLoadedProvider( + bool show_assets, + bool show_offline_pages, + std::unique_ptr<base::Clock> clock) { + CreateProvider(show_assets, show_offline_pages, std::move(clock)); FireHistoryQueryComplete(); return provider_.get(); } - DownloadSuggestionsProvider* CreateProvider(bool show_assets, - bool show_offline_pages) { + DownloadSuggestionsProvider* CreateProvider( + bool show_assets, + bool show_offline_pages, + std::unique_ptr<base::Clock> clock) { DCHECK(!provider_); DCHECK(show_assets || show_offline_pages); @@ -285,7 +290,7 @@ provider_ = base::MakeUnique<DownloadSuggestionsProvider>( &observer_, show_offline_pages ? &offline_pages_model_ : nullptr, show_assets ? &downloads_manager_ : nullptr, &download_history_, - pref_service()); + pref_service(), std::move(clock)); return provider_.get(); } @@ -386,7 +391,8 @@ HasDownloadSuggestionExtra( /*is_download_asset=*/false, FILE_PATH_LITERAL(""), ""))))); - CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true, + base::MakeUnique<base::DefaultClock>()); } TEST_F(DownloadSuggestionsProviderTest, @@ -396,7 +402,8 @@ EXPECT_CALL(*observer(), OnNewSuggestions(_, downloads_category(), SizeIs(0))); - CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true, + base::MakeUnique<base::DefaultClock>()); std::vector<std::unique_ptr<FakeDownloadItem>> asset_downloads = CreateDummyAssetDownloads({1, 2}); @@ -437,7 +444,8 @@ UnorderedElementsAre( HasUrl("http://dummy.com/1"), HasUrl("http://dummy.com/2")))); - CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true, + base::MakeUnique<base::DefaultClock>()); std::vector<std::unique_ptr<FakeDownloadItem>> asset_downloads = CreateDummyAssetDownloads({1, 2}); @@ -464,39 +472,49 @@ IgnoreOnCategoryStatusChangedToAvailable(); IgnoreOnSuggestionInvalidated(); - base::Time now = base::Time::Now(); - base::Time yesterday = now - base::TimeDelta::FromDays(1); - base::Time tomorrow = now + base::TimeDelta::FromDays(1); - base::Time next_week = now + base::TimeDelta::FromDays(7); + std::vector<OfflinePageItem> offline_pages = CreateDummyOfflinePages({0, 1}); - (*offline_pages_model()->mutable_items()) - .push_back(CreateDummyOfflinePage(1, yesterday)); - (*offline_pages_model()->mutable_items()) - .push_back(CreateDummyOfflinePage(2, tomorrow)); + offline_pages[0].url = GURL("http://dummy.com/0"); + offline_pages[0].creation_time = now - base::TimeDelta::FromMinutes(10); + offline_pages[0].last_access_time = offline_pages[0].creation_time; + + offline_pages[1].url = GURL("http://dummy.com/1"); + offline_pages[1].creation_time = now - base::TimeDelta::FromMinutes(5); + offline_pages[1].last_access_time = offline_pages[1].creation_time; + + *(offline_pages_model()->mutable_items()) = offline_pages; + + auto test_clock = base::MakeUnique<base::SimpleTestClock>(); + test_clock->SetNow(now); + EXPECT_CALL(*observer(), + OnNewSuggestions(_, downloads_category(), + ElementsAre(HasUrl("http://dummy.com/1"), + HasUrl("http://dummy.com/0")))); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true, + std::move(test_clock)); + + std::vector<std::unique_ptr<FakeDownloadItem>> asset_downloads = + CreateDummyAssetDownloads({2, 3}); + + asset_downloads[0]->SetURL(GURL("http://download.com/2")); + asset_downloads[0]->SetStartTime(now - base::TimeDelta::FromMinutes(3)); + + asset_downloads[1]->SetURL(GURL("http://download.com/3")); + asset_downloads[1]->SetStartTime(now - base::TimeDelta::FromMinutes(7)); EXPECT_CALL(*observer(), OnNewSuggestions(_, downloads_category(), - ElementsAre(HasUrl("http://dummy.com/2"), - HasUrl("http://dummy.com/1")))); - CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true); - - std::vector<std::unique_ptr<FakeDownloadItem>> asset_downloads; - asset_downloads.push_back(CreateDummyAssetDownload(3, next_week)); - asset_downloads.push_back(CreateDummyAssetDownload(4, now)); - - EXPECT_CALL(*observer(), - OnNewSuggestions(_, downloads_category(), - ElementsAre(HasUrl("http://download.com/3"), - HasUrl("http://dummy.com/2"), - HasUrl("http://dummy.com/1")))); + ElementsAre(HasUrl("http://download.com/2"), + HasUrl("http://dummy.com/1"), + HasUrl("http://dummy.com/0")))); FireDownloadCreated(asset_downloads[0].get()); EXPECT_CALL(*observer(), OnNewSuggestions(_, downloads_category(), - ElementsAre(HasUrl("http://download.com/3"), - HasUrl("http://dummy.com/2"), - HasUrl("http://download.com/4"), - HasUrl("http://dummy.com/1")))); + ElementsAre(HasUrl("http://download.com/2"), + HasUrl("http://dummy.com/1"), + HasUrl("http://download.com/3"), + HasUrl("http://dummy.com/0")))); FireDownloadCreated(asset_downloads[1].get()); } @@ -513,7 +531,8 @@ HasUrl("http://dummy.com/2"), HasUrl("http://download.com/1"), HasUrl("http://download.com/2")))); - CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true, + base::MakeUnique<base::DefaultClock>()); EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0); EXPECT_CALL(*observer(), OnSuggestionInvalidated(_, _)).Times(0); @@ -539,7 +558,8 @@ HasUrl("http://dummy.com/2"), HasUrl("http://download.com/1"), HasUrl("http://download.com/2")))); - CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true, + base::MakeUnique<base::DefaultClock>()); provider()->DismissSuggestion( GetDummySuggestionId(1, /*is_offline_page=*/true)); @@ -567,7 +587,8 @@ HasUrl("http://dummy.com/2"), HasUrl("http://download.com/1"), HasUrl("http://download.com/2")))); - CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true, + base::MakeUnique<base::DefaultClock>()); provider()->DismissSuggestion( GetDummySuggestionId(1, /*is_offline_page=*/true)); @@ -591,7 +612,8 @@ HasUrl("http://dummy.com/2"), HasUrl("http://download.com/1"), HasUrl("http://download.com/2")))); - CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true, + base::MakeUnique<base::DefaultClock>()); provider()->DismissSuggestion( GetDummySuggestionId(1, /*is_offline_page=*/true)); @@ -622,7 +644,8 @@ HasUrl("http://dummy.com/2"), HasUrl("http://download.com/1"), HasUrl("http://download.com/2")))); - CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true, + base::MakeUnique<base::DefaultClock>()); provider()->DismissSuggestion( GetDummySuggestionId(1, /*is_offline_page=*/true)); @@ -652,7 +675,8 @@ HasUrl("http://download.com/3"), HasUrl("http://download.com/4"), HasUrl("http://download.com/5")))); - CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true, + base::MakeUnique<base::DefaultClock>()); provider()->DismissSuggestion( GetDummySuggestionId(1, /*is_offline_page=*/false)); @@ -684,7 +708,8 @@ UnorderedElementsAre(HasUrl("http://dummy.com/1"), HasUrl("http://dummy.com/2"), HasUrl("http://download.com/1")))); - CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true, + base::MakeUnique<base::DefaultClock>()); // We add another item manually, so that when it gets deleted it is not // present in DownloadsManager list. @@ -724,7 +749,8 @@ HasUrl("http://download.com/3"), HasUrl("http://download.com/4"), HasUrl("http://download.com/5")))); - CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true, + base::MakeUnique<base::DefaultClock>()); // Note that |CreateDummyAssetDownloads| creates items "downloaded" before // |base::Time::Now()|, so for a new item the time is set in future to enforce @@ -768,7 +794,8 @@ HasUrl("http://dummy.com/1"), HasUrl("http://dummy.com/2"), HasUrl("http://dummy.com/3")))); - CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true, + base::MakeUnique<base::DefaultClock>()); provider()->DismissSuggestion( GetDummySuggestionId(1, /*is_offline_page=*/true)); @@ -798,7 +825,8 @@ OnNewSuggestions(_, downloads_category(), UnorderedElementsAre(HasUrl("http://download.com/1"), HasUrl("http://download.com/2")))); - CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true, + base::MakeUnique<base::DefaultClock>()); provider()->DismissSuggestion( GetDummySuggestionId(1, /*is_offline_page=*/false)); @@ -819,7 +847,8 @@ OnNewSuggestions(_, downloads_category(), UnorderedElementsAre(HasUrl("http://download.com/1"), HasUrl("http://download.com/2")))); - CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true, + base::MakeUnique<base::DefaultClock>()); } TEST_F(DownloadSuggestionsProviderTest, @@ -832,7 +861,8 @@ UnorderedElementsAre( HasUrl("http://dummy.com/1"), HasUrl("http://dummy.com/2")))); - CreateProvider(/*show_assets=*/false, /*show_offline_pages=*/true); + CreateProvider(/*show_assets=*/false, /*show_offline_pages=*/true, + base::MakeUnique<base::DefaultClock>()); FireOfflinePageModelLoaded(); } @@ -841,7 +871,8 @@ IgnoreOnCategoryStatusChangedToAvailable(); EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0); - CreateProvider(/*show_assets=*/true, /*show_offline_pages=*/true); + CreateProvider(/*show_assets=*/true, /*show_offline_pages=*/true, + base::MakeUnique<base::DefaultClock>()); *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({1, 2}); EXPECT_CALL( @@ -861,7 +892,8 @@ *observer(), OnNewSuggestions(_, downloads_category(), UnorderedElementsAre(HasUrl("http://download.com/1")))); - CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true, + base::MakeUnique<base::DefaultClock>()); EXPECT_CALL(*observer(), OnSuggestionInvalidated( @@ -878,7 +910,8 @@ *(offline_pages_model()->mutable_items()) = CreateDummyOfflinePages({1, 2}); EXPECT_CALL(*observer(), OnNewSuggestions(_, downloads_category(), IsEmpty())); - CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/false); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/false, + base::MakeUnique<base::DefaultClock>()); std::vector<std::unique_ptr<FakeDownloadItem>> asset_downloads = CreateDummyAssetDownloads({1}); @@ -900,7 +933,8 @@ UnorderedElementsAre( HasUrl("http://dummy.com/1"), HasUrl("http://dummy.com/2")))); - CreateProvider(/*show_assets=*/false, /*show_offline_pages=*/true); + CreateProvider(/*show_assets=*/false, /*show_offline_pages=*/true, + base::MakeUnique<base::DefaultClock>()); downloads_manager()->NotifyDownloadCreated( downloads_manager()->items()[0].get()); // This notification should not reach the provider, because the asset @@ -920,7 +954,8 @@ OnNewSuggestions(_, downloads_category(), UnorderedElementsAre(HasUrl("http://download.com/1"), HasUrl("http://download.com/2")))); - CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/false); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/false, + base::MakeUnique<base::DefaultClock>()); } TEST_F(DownloadSuggestionsProviderTest, @@ -934,7 +969,8 @@ UnorderedElementsAre( HasUrl("http://dummy.com/1"), HasUrl("http://dummy.com/2")))); - CreateProvider(/*show_assets=*/false, /*show_offline_pages=*/true); + CreateProvider(/*show_assets=*/false, /*show_offline_pages=*/true, + base::MakeUnique<base::DefaultClock>()); } TEST_F(DownloadSuggestionsProviderTest, ShouldStoreDismissedSuggestions) { @@ -945,7 +981,8 @@ *(offline_pages_model()->mutable_items()) = CreateDummyOfflinePages({1}); *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({1}); EXPECT_CALL(*observer(), OnNewSuggestions(_, downloads_category(), _)); - CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true, + base::MakeUnique<base::DefaultClock>()); provider()->DismissSuggestion( GetDummySuggestionId(1, /*is_offline_page=*/true)); provider()->DismissSuggestion( @@ -954,7 +991,8 @@ DestroyProvider(); EXPECT_CALL(*observer(), OnNewSuggestions(_, downloads_category(), _)); - CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true, + base::MakeUnique<base::DefaultClock>()); EXPECT_THAT(GetDismissedSuggestions(), UnorderedElementsAre(HasUrl("http://dummy.com/1"), HasUrl("http://download.com/1"))); @@ -968,7 +1006,8 @@ // Dismiss items to store them in the list of dismissed items. *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({1}); EXPECT_CALL(*observer(), OnNewSuggestions(_, downloads_category(), _)); - CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/false); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/false, + base::MakeUnique<base::DefaultClock>()); provider()->DismissSuggestion( GetDummySuggestionId(1, /*is_offline_page=*/false)); ASSERT_THAT(GetDismissedSuggestions(), @@ -979,7 +1018,8 @@ downloads_manager()->mutable_items()->clear(); EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0); - CreateProvider(/*show_assets=*/true, /*show_offline_pages=*/false); + CreateProvider(/*show_assets=*/true, /*show_offline_pages=*/false, + base::MakeUnique<base::DefaultClock>()); // Dismissed IDs should not be pruned yet, because the downloads list at the // manager is not complete. @@ -996,3 +1036,83 @@ // Once the manager has been loaded, the ids should be pruned. EXPECT_THAT(GetDismissedSuggestions(), IsEmpty()); } + +TEST_F(DownloadSuggestionsProviderTest, ShouldNotShowOutdatedDownloads) { + IgnoreOnCategoryStatusChangedToAvailable(); + IgnoreOnSuggestionInvalidated(); + + const base::Time not_outdated = + now - base::TimeDelta::FromHours(kDefaultMaxDownloadAgeHours) + + base::TimeDelta::FromSeconds(1); + const base::Time outdated = + now - base::TimeDelta::FromHours(kDefaultMaxDownloadAgeHours) - + base::TimeDelta::FromSeconds(1); + + *(offline_pages_model()->mutable_items()) = CreateDummyOfflinePages({0, 1}); + + offline_pages_model()->mutable_items()->at(0).url = + GURL("http://dummy.com/0"); + offline_pages_model()->mutable_items()->at(0).creation_time = not_outdated; + offline_pages_model()->mutable_items()->at(0).last_access_time = not_outdated; + + offline_pages_model()->mutable_items()->at(1).url = + GURL("http://dummy.com/1"); + offline_pages_model()->mutable_items()->at(1).creation_time = outdated; + offline_pages_model()->mutable_items()->at(1).last_access_time = outdated; + + *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({0, 1}); + + downloads_manager()->mutable_items()->at(0)->SetURL( + GURL("http://download.com/0")); + downloads_manager()->mutable_items()->at(0)->SetStartTime(not_outdated); + + downloads_manager()->mutable_items()->at(1)->SetURL( + GURL("http://download.com/1")); + downloads_manager()->mutable_items()->at(1)->SetStartTime(outdated); + + EXPECT_CALL( + *observer(), + OnNewSuggestions(_, downloads_category(), + UnorderedElementsAre(HasUrl("http://dummy.com/0"), + HasUrl("http://download.com/0")))); + auto test_clock = base::MakeUnique<base::SimpleTestClock>(); + test_clock->SetNow(now); + CreateLoadedProvider(/*show_assets=*/true, /*show_offline_pages=*/true, + std::move(test_clock)); +} + +TEST_F(DownloadSuggestionsProviderTest, + ShouldShowRecentlyVisitedOfflinePageDownloads) { + IgnoreOnCategoryStatusChangedToAvailable(); + IgnoreOnSuggestionInvalidated(); + + const base::Time not_outdated = + now - base::TimeDelta::FromHours(kDefaultMaxDownloadAgeHours) + + base::TimeDelta::FromSeconds(1); + const base::Time outdated = + now - base::TimeDelta::FromHours(kDefaultMaxDownloadAgeHours) - + base::TimeDelta::FromSeconds(1); + + std::vector<OfflinePageItem> offline_pages = CreateDummyOfflinePages({0, 1}); + + offline_pages[0].url = GURL("http://dummy.com/0"); + offline_pages[0].creation_time = outdated; + offline_pages[0].last_access_time = not_outdated; + + offline_pages[1].url = GURL("http://dummy.com/1"); + offline_pages[1].creation_time = outdated; + offline_pages[1].last_access_time = offline_pages[1].creation_time; + + *(offline_pages_model()->mutable_items()) = offline_pages; + + // Even though page 0 was created long time ago, it should be reported because + // it has been visited recently. + EXPECT_CALL( + *observer(), + OnNewSuggestions(_, downloads_category(), + UnorderedElementsAre(HasUrl("http://dummy.com/0")))); + auto test_clock = base::MakeUnique<base::SimpleTestClock>(); + test_clock->SetNow(now); + CreateProvider(/*show_assets=*/false, /*show_offline_pages=*/true, + std::move(test_clock)); +}
diff --git a/chrome/browser/ntp_snippets/ntp_snippets_features.cc b/chrome/browser/ntp_snippets/ntp_snippets_features.cc index 65b70ba..88e281f4 100644 --- a/chrome/browser/ntp_snippets/ntp_snippets_features.cc +++ b/chrome/browser/ntp_snippets/ntp_snippets_features.cc
@@ -9,5 +9,7 @@ const char kContentSuggestionsNotificationsAlwaysNotifyParam[] = "always_notify"; +const char kContentSuggestionsNotificationsUseSnippetAsTextParam[] = + "use_snippet_as_text"; const char kContentSuggestionsNotificationsIgnoredLimitParam[] = "ignored_limit";
diff --git a/chrome/browser/ntp_snippets/ntp_snippets_features.h b/chrome/browser/ntp_snippets/ntp_snippets_features.h index 5e7817c..2e67d86 100644 --- a/chrome/browser/ntp_snippets/ntp_snippets_features.h +++ b/chrome/browser/ntp_snippets/ntp_snippets_features.h
@@ -14,6 +14,10 @@ // "true": always send a notification when we receive ARTICLES suggestions extern const char kContentSuggestionsNotificationsAlwaysNotifyParam[]; +// "true": use article's snippet as notification's text +// "false": use article's publisher as notification's text +extern const char kContentSuggestionsNotificationsUseSnippetAsTextParam[]; + // An integer. The number of notifications that can be ignored. If the user // ignores this many notifications or more, we stop sending them. extern const char kContentSuggestionsNotificationsIgnoredLimitParam[];
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc index 3fe20efd..a9c4f95a 100644 --- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc +++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -515,8 +515,15 @@ internal::kHistogramParseStartToFirstMeaningfulPaint, 0); } +// Flaky on Linux (timing out or failing in an expectation) crbug.com/657022 +#if defined(OS_LINUX) +#define MAYBE_NoStatePrefetchObserverCacheable \ + DISABLED_NoStatePrefetchObserverCacheable +#else +#define MAYBE_NoStatePrefetchObserverCacheable NoStatePrefetchObserverCacheable +#endif IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest, - NoStatePrefetchObserverCacheable) { + MAYBE_NoStatePrefetchObserverCacheable) { ASSERT_TRUE(embedded_test_server()->Start()); ui_test_utils::NavigateToURL(browser(), @@ -529,8 +536,15 @@ "Prerender.none_PrefetchTTFCP.Reference.Cacheable.Visible", 1); } +// Flaky on Linux (timing out or failing in an expectation) crbug.com/657022 +#if defined(OS_LINUX) +#define MAYBE_NoStatePrefetchObserverNoStore \ + DISABLED_NoStatePrefetchObserverNoStore +#else +#define MAYBE_NoStatePrefetchObserverNoStore NoStatePrefetchObserverNoStore +#endif IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest, - NoStatePrefetchObserverNoStore) { + MAYBE_NoStatePrefetchObserverNoStore) { ASSERT_TRUE(embedded_test_server()->Start()); ui_test_utils::NavigateToURL(browser(),
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc index 62bd1646..9928f5fdb 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client.cc +++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -60,6 +60,8 @@ #include "extensions/features/features.h" #include "google_apis/gaia/gaia_urls.h" #include "net/base/url_util.h" +#include "net/http/transport_security_state.h" +#include "net/url_request/url_request_context.h" #include "third_party/re2/src/re2/re2.h" #if defined(OS_ANDROID) @@ -223,6 +225,22 @@ IsPasswordManagementEnabledForCurrentPage(); } +bool ChromePasswordManagerClient::IsHSTSActiveForHost( + const GURL& origin) const { + if (!origin.is_valid()) + return false; + + net::TransportSecurityState* security_state = + profile_->GetRequestContext() + ->GetURLRequestContext() + ->transport_security_state(); + + if (!security_state) + return false; + + return security_state->ShouldUpgradeToSSL(origin.host()); +} + bool ChromePasswordManagerClient::OnCredentialManagerUsed() { prerender::PrerenderContents* prerender_contents = prerender::PrerenderContents::FromWebContents(web_contents());
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h index 67a98b1..d1edf73 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client.h +++ b/chrome/browser/password_manager/chrome_password_manager_client.h
@@ -49,6 +49,7 @@ bool IsAutomaticPasswordSavingEnabled() const override; bool IsSavingAndFillingEnabledForCurrentPage() const override; bool IsFillingEnabledForCurrentPage() const override; + bool IsHSTSActiveForHost(const GURL& origin) const override; bool OnCredentialManagerUsed() override; bool PromptUserToSaveOrUpdatePassword( std::unique_ptr<password_manager::PasswordFormManager> form_to_save,
diff --git a/chrome/browser/password_manager/password_manager_test_base.cc b/chrome/browser/password_manager/password_manager_test_base.cc index e8d0327..d86aa853 100644 --- a/chrome/browser/password_manager/password_manager_test_base.cc +++ b/chrome/browser/password_manager/password_manager_test_base.cc
@@ -95,10 +95,6 @@ void BubbleObserver::Dismiss() const { passwords_ui_controller_->OnBubbleHidden(); - // Navigate away to reset the state to inactive. - static_cast<content::WebContentsObserver*>(passwords_ui_controller_) - ->DidNavigateMainFrame(content::LoadCommittedDetails(), - content::FrameNavigateParams()); ASSERT_EQ(password_manager::ui::INACTIVE_STATE, passwords_ui_controller_->GetState()); }
diff --git a/chrome/browser/pepper_flash_settings_manager.cc b/chrome/browser/pepper_flash_settings_manager.cc index c1e2d35..c9a7155 100644 --- a/chrome/browser/pepper_flash_settings_manager.cc +++ b/chrome/browser/pepper_flash_settings_manager.cc
@@ -13,6 +13,7 @@ #include "base/files/file_util.h" #include "base/sequenced_task_runner_helpers.h" #include "base/strings/utf_string_conversions.h" +#include "base/task_scheduler/post_task.h" #include "build/build_config.h" #include "chrome/browser/plugins/plugin_prefs.h" #include "chrome/browser/profiles/profile.h" @@ -125,9 +126,8 @@ void InitializeOnIOThread(); void DeauthorizeContentLicensesOnIOThread(uint32_t request_id); - void DeauthorizeContentLicensesOnBlockingPool( - uint32_t request_id, - const base::FilePath& profile_path); + void DeauthorizeContentLicensesAsync(uint32_t request_id, + const base::FilePath& profile_path); void DeauthorizeContentLicensesInPlugin(uint32_t request_id, bool success); void GetPermissionSettingsOnIOThread( uint32_t request_id, @@ -442,9 +442,11 @@ } #if defined(OS_CHROMEOS) - BrowserThread::PostBlockingPoolTask(FROM_HERE, - base::Bind(&Core::DeauthorizeContentLicensesOnBlockingPool, this, - request_id, browser_context_path_)); + base::PostTaskWithTraits(FROM_HERE, + base::TaskTraits().MayBlock().WithPriority( + base::TaskPriority::BACKGROUND), + base::Bind(&Core::DeauthorizeContentLicensesAsync, + this, request_id, browser_context_path_)); #else DeauthorizeContentLicensesInPlugin(request_id, true); #endif @@ -453,7 +455,7 @@ // TODO(raymes): This is temporary code to migrate ChromeOS devices to the new // scheme for generating device IDs. Delete this once we are sure most ChromeOS // devices have been migrated. -void PepperFlashSettingsManager::Core::DeauthorizeContentLicensesOnBlockingPool( +void PepperFlashSettingsManager::Core::DeauthorizeContentLicensesAsync( uint32_t request_id, const base::FilePath& profile_path) { // ChromeOS used to store the device ID in a file but this is no longer used.
diff --git a/chrome/browser/permissions/permission_blacklist_client.cc b/chrome/browser/permissions/permission_blacklist_client.cc index ef0be9b3..35386710 100644 --- a/chrome/browser/permissions/permission_blacklist_client.cc +++ b/chrome/browser/permissions/permission_blacklist_client.cc
@@ -41,7 +41,7 @@ callback_(callback), timeout_(timeout), is_active_(true) { - // Balanced by a call to Release() in OnCheckApiBlacklistUrlResult(). + // Balanced by a call to Release() in EvaluateBlacklistResultOnUiThread(). AddRef(); content::BrowserThread::PostTask( content::BrowserThread::IO, FROM_HERE, @@ -61,14 +61,16 @@ FROM_HERE, base::TimeDelta::FromMilliseconds(timeout_), base::Bind(&PermissionBlacklistClient::OnCheckApiBlacklistUrlResult, this, request_origin, empty_metadata)); - db_manager_->CheckApiBlacklistUrl(request_origin, this); + // If CheckApiBlacklistUrl returns true, no asynchronous call to |this| will + // be made, so just directly call through to OnCheckApiBlacklistUrlResult. + if (db_manager_->CheckApiBlacklistUrl(request_origin, this)) + OnCheckApiBlacklistUrlResult(request_origin, empty_metadata); } void PermissionBlacklistClient::OnCheckApiBlacklistUrlResult( const GURL& url, const safe_browsing::ThreatMetadata& metadata) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - if (timer_->IsRunning()) timer_->Stop(); else
diff --git a/chrome/browser/permissions/permission_context_base_unittest.cc b/chrome/browser/permissions/permission_context_base_unittest.cc index 44e469cd..888e537e 100644 --- a/chrome/browser/permissions/permission_context_base_unittest.cc +++ b/chrome/browser/permissions/permission_context_base_unittest.cc
@@ -55,6 +55,8 @@ const char* const kPromptGroupName = kPermissionsKillSwitchTestGroup; const char kPromptTrialName[] = "PermissionPromptsUX"; +namespace { + class MockSafeBrowsingDatabaseManager : public safe_browsing::TestSafeBrowsingDatabaseManager { public: @@ -96,6 +98,8 @@ DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingDatabaseManager); }; +} // namespace + class TestPermissionContext : public PermissionContextBase { public: TestPermissionContext(Profile* profile,
diff --git a/chrome/browser/permissions/permission_decision_auto_blocker.cc b/chrome/browser/permissions/permission_decision_auto_blocker.cc index 3f83a91..9bf499f 100644 --- a/chrome/browser/permissions/permission_decision_auto_blocker.cc +++ b/chrome/browser/permissions/permission_decision_auto_blocker.cc
@@ -7,7 +7,6 @@ #include <memory> #include "base/feature_list.h" -#include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/strings/string_number_conversions.h" #include "base/values.h"
diff --git a/chrome/browser/permissions/permission_decision_auto_blocker_unittest.cc b/chrome/browser/permissions/permission_decision_auto_blocker_unittest.cc index e1ddba5..04b412c3 100644 --- a/chrome/browser/permissions/permission_decision_auto_blocker_unittest.cc +++ b/chrome/browser/permissions/permission_decision_auto_blocker_unittest.cc
@@ -29,17 +29,20 @@ return true; } -} // namespace - class MockSafeBrowsingDatabaseManager : public safe_browsing::TestSafeBrowsingDatabaseManager { public: - explicit MockSafeBrowsingDatabaseManager(bool perform_callback) - : perform_callback_(perform_callback) {} + explicit MockSafeBrowsingDatabaseManager(bool perform_callback, bool enabled) + : perform_callback_(perform_callback), enabled_(enabled) {} bool CheckApiBlacklistUrl( const GURL& url, safe_browsing::SafeBrowsingDatabaseManager::Client* client) override { + // Return true when able to synchronously determine that the url is safe. + if (!enabled_) { + return true; + } + if (perform_callback_) { safe_browsing::ThreatMetadata metadata; const auto& blacklisted_permissions = permissions_blacklist_.find(url); @@ -70,11 +73,14 @@ private: bool perform_callback_; + bool enabled_; std::map<GURL, std::set<std::string>> permissions_blacklist_; DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingDatabaseManager); }; +} // namespace + class PermissionDecisionAutoBlockerUnitTest : public ChromeRenderViewHostTestHarness { protected: @@ -89,6 +95,7 @@ base::MakeUnique<base::SimpleTestClock>(); clock_ = clock.get(); autoblocker_->SetClockForTesting(std::move(clock)); + callback_was_run_ = false; } void SetSafeBrowsingDatabaseManagerAndTimeoutForTesting( @@ -121,6 +128,7 @@ PermissionDecisionAutoBlocker* autoblocker() { return autoblocker_; } void SetLastEmbargoStatus(base::Closure quit_closure, bool status) { + callback_was_run_ = true; last_embargoed_status_ = status; if (quit_closure) { quit_closure.Run(); @@ -130,6 +138,8 @@ bool last_embargoed_status() { return last_embargoed_status_; } + bool callback_was_run() { return callback_was_run_; } + base::SimpleTestClock* clock() { return clock_; } const char* GetDismissKey() { @@ -145,6 +155,7 @@ base::test::ScopedFeatureList feature_list_; base::SimpleTestClock* clock_; bool last_embargoed_status_; + bool callback_was_run_; }; TEST_F(PermissionDecisionAutoBlockerUnitTest, RemoveCountsByUrl) { @@ -256,13 +267,15 @@ GURL url("https://www.google.com"); scoped_refptr<MockSafeBrowsingDatabaseManager> db_manager = - new MockSafeBrowsingDatabaseManager(true /* perform_callback */); + new MockSafeBrowsingDatabaseManager(true /* perform_callback */, + true /* enabled */); std::set<std::string> blacklisted_permissions{"GEOLOCATION"}; db_manager->BlacklistUrlPermissions(url, blacklisted_permissions); SetSafeBrowsingDatabaseManagerAndTimeoutForTesting(db_manager, 2000 /* timeout in ms */); UpdateEmbargoedStatus(content::PermissionType::GEOLOCATION, url); + EXPECT_TRUE(callback_was_run()); EXPECT_TRUE(last_embargoed_status()); } @@ -379,13 +392,15 @@ clock()->SetNow(base::Time::Now()); scoped_refptr<MockSafeBrowsingDatabaseManager> db_manager = - new MockSafeBrowsingDatabaseManager(false /* perform_callback */); + new MockSafeBrowsingDatabaseManager(false /* perform_callback */, + true /* enabled */); std::set<std::string> blacklisted_permissions{"GEOLOCATION"}; db_manager->BlacklistUrlPermissions(url, blacklisted_permissions); SetSafeBrowsingDatabaseManagerAndTimeoutForTesting(db_manager, 0 /* timeout in ms */); UpdateEmbargoedStatus(content::PermissionType::GEOLOCATION, url); + EXPECT_TRUE(callback_was_run()); EXPECT_FALSE(last_embargoed_status()); EXPECT_FALSE( autoblocker()->IsUnderEmbargo(content::PermissionType::GEOLOCATION, url)); @@ -395,6 +410,7 @@ clock()->Advance(base::TimeDelta::FromDays(1)); UpdateEmbargoedStatus(content::PermissionType::GEOLOCATION, url); + EXPECT_TRUE(callback_was_run()); EXPECT_TRUE(last_embargoed_status()); clock()->Advance(base::TimeDelta::FromDays(1)); @@ -473,3 +489,19 @@ EXPECT_EQ(50, autoblocker()->GetIgnoreCount( url, content::PermissionType::GEOLOCATION)); } + +// Test that a blacklisted permission should not be autoblocked if the database +// manager is disabled. +TEST_F(PermissionDecisionAutoBlockerUnitTest, TestDisabledDatabaseManager) { + GURL url("https://www.google.com"); + scoped_refptr<MockSafeBrowsingDatabaseManager> db_manager = + new MockSafeBrowsingDatabaseManager(true /* perform_callback */, + false /* enabled */); + std::set<std::string> blacklisted_permissions{"GEOLOCATION"}; + db_manager->BlacklistUrlPermissions(url, blacklisted_permissions); + SetSafeBrowsingDatabaseManagerAndTimeoutForTesting(db_manager, + 2000 /* timeout in ms */); + UpdateEmbargoedStatus(content::PermissionType::GEOLOCATION, url); + EXPECT_TRUE(callback_was_run()); + EXPECT_FALSE(last_embargoed_status()); +}
diff --git a/chrome/browser/platform_util.cc b/chrome/browser/platform_util.cc index 5cd2e45..8ad9fb6 100644 --- a/chrome/browser/platform_util.cc +++ b/chrome/browser/platform_util.cc
@@ -7,6 +7,7 @@ #include "base/files/file.h" #include "base/files/file_util.h" #include "base/logging.h" +#include "base/task_scheduler/post_task.h" #include "chrome/browser/platform_util_internal.h" #include "content/public/browser/browser_thread.h" @@ -57,9 +58,11 @@ OpenItemType item_type, const OpenOperationCallback& callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - BrowserThread::PostBlockingPoolTask( - FROM_HERE, base::Bind(&VerifyAndOpenItemOnBlockingThread, full_path, - item_type, callback)); + base::PostTaskWithTraits(FROM_HERE, + base::TaskTraits().MayBlock().WithPriority( + base::TaskPriority::BACKGROUND), + base::Bind(&VerifyAndOpenItemOnBlockingThread, + full_path, item_type, callback)); } } // namespace platform_util
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index f28f1ce5..36712d08 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -20,6 +20,7 @@ #include "chrome/browser/custom_handlers/protocol_handler_registry.h" #include "chrome/browser/devtools/devtools_window.h" #include "chrome/browser/download/download_prefs.h" +#include "chrome/browser/engagement/important_sites_util.h" #include "chrome/browser/external_protocol/external_protocol_handler.h" #include "chrome/browser/first_run/first_run.h" #include "chrome/browser/geolocation/geolocation_prefs.h" @@ -488,6 +489,7 @@ dom_distiller::DistilledPagePrefs::RegisterProfilePrefs(registry); DownloadPrefs::RegisterProfilePrefs(registry); HostContentSettingsMap::RegisterProfilePrefs(registry); + ImportantSitesUtil::RegisterProfilePrefs(registry); IncognitoModePrefs::RegisterProfilePrefs(registry); InstantUI::RegisterProfilePrefs(registry); NavigationCorrectionTabObserver::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/prefs/incognito_mode_prefs.cc b/chrome/browser/prefs/incognito_mode_prefs.cc index b69acbbf4..852698b 100644 --- a/chrome/browser/prefs/incognito_mode_prefs.cc +++ b/chrome/browser/prefs/incognito_mode_prefs.cc
@@ -10,6 +10,7 @@ #include "base/logging.h" #include "base/macros.h" #include "base/metrics/histogram_macros.h" +#include "base/task_scheduler/post_task.h" #include "base/threading/thread_restrictions.h" #include "base/time/time.h" #include "build/build_config.h" @@ -197,8 +198,11 @@ #if defined(OS_WIN) // static void IncognitoModePrefs::InitializePlatformParentalControls() { - content::BrowserThread::PostBlockingPoolTask( - FROM_HERE, + // TODO(fdoray): This task uses COM. Add the WithCom() trait once supported. + // crbug.com/662122 + base::PostTaskWithTraits( + FROM_HERE, base::TaskTraits().MayBlock().WithPriority( + base::TaskPriority::USER_VISIBLE), base::Bind( base::IgnoreResult(&PlatformParentalControlsValue::GetInstance))); }
diff --git a/chrome/browser/process_resource_usage.h b/chrome/browser/process_resource_usage.h index 9c37540..aa8cd10cd 100644 --- a/chrome/browser/process_resource_usage.h +++ b/chrome/browser/process_resource_usage.h
@@ -13,7 +13,7 @@ #include "base/macros.h" #include "base/threading/thread_checker.h" #include "chrome/common/resource_usage_reporter.mojom.h" -#include "third_party/WebKit/public/web/WebCache.h" +#include "third_party/WebKit/public/platform/WebCache.h" // Provides resource usage information about a child process. //
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc index 8961ab8..60cf509 100644 --- a/chrome/browser/profiles/profile_io_data.cc +++ b/chrome/browser/profiles/profile_io_data.cc
@@ -1304,7 +1304,7 @@ return base::MakeUnique<net::HttpCache>( base::WrapUnique(new DevToolsNetworkTransactionFactory( network_controller_handle_.GetController(), session)), - std::move(main_backend), true /* set_up_quic_server_info */); + std::move(main_backend), true /* is_main_cache */); } std::unique_ptr<net::HttpCache> ProfileIOData::CreateHttpFactory( @@ -1315,7 +1315,7 @@ return base::MakeUnique<net::HttpCache>( base::WrapUnique(new DevToolsNetworkTransactionFactory( network_controller_handle_.GetController(), shared_session)), - std::move(backend), false /* set_up_quic_server_info */); + std::move(backend), false /* is_main_cache */); } void ProfileIOData::SetCookieSettingsForTesting(
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn index 6a19ea70..c8edb250 100644 --- a/chrome/browser/resources/BUILD.gn +++ b/chrome/browser/resources/BUILD.gn
@@ -150,4 +150,15 @@ ] output_dir = "$root_gen_dir/chrome" } + + grit("webapks_ui_resources") { + source = "webapks_ui_resources.grd" + use_qualified_include = true + defines = chrome_grit_defines + outputs = [ + "grit/webapks_ui_resources.h", + "webapks_ui_resources.pak", + ] + output_dir = "$root_gen_dir/chrome" + } }
diff --git a/chrome/browser/resources/OWNERS b/chrome/browser/resources/OWNERS index 2a7090f..d2b4bc4 100644 --- a/chrome/browser/resources/OWNERS +++ b/chrome/browser/resources/OWNERS
@@ -11,6 +11,7 @@ per-file component_extension_resources.grd=dgozman@chromium.org per-file profile_signin_confirmation*=achuith@chromium.org +per-file snippets_internals*=file://components/ntp_snippets/OWNERS per-file sync_file_system_internals_resources.*=tzik@chromium.org # COMPONENT: UI
diff --git a/chrome/browser/resources/PRESUBMIT.py b/chrome/browser/resources/PRESUBMIT.py index 9dac919..38260bc 100644 --- a/chrome/browser/resources/PRESUBMIT.py +++ b/chrome/browser/resources/PRESUBMIT.py
@@ -91,12 +91,26 @@ any(input_api.re.search(type_re, match.group(i)) for i in (1, 3))) +def RunVulcanizeTests(input_api, output_api): + presubmit_path = input_api.PresubmitLocalPath() + tests = [input_api.os_path.join(presubmit_path, 'vulcanize_gn_test.py')] + return input_api.canned_checks.RunUnitTests(input_api, output_api, tests) + + +def _CheckChangeOnUploadOrCommit(input_api, output_api): + results = CheckUserActionUpdate(input_api, output_api, ACTION_XML_PATH) + affected = input_api.AffectedFiles() + if any(f for f in affected if f.LocalPath().endswith('vulcanize_gn.py')): + results += RunVulcanizeTests(input_api, output_api) + return results + + def CheckChangeOnUpload(input_api, output_api): - return CheckUserActionUpdate(input_api, output_api, ACTION_XML_PATH) + return _CheckChangeOnUploadOrCommit(input_api, output_api) def CheckChangeOnCommit(input_api, output_api): - return CheckUserActionUpdate(input_api, output_api, ACTION_XML_PATH) + return _CheckChangeOnUploadOrCommit(input_api, output_api) def PostUploadHook(cl, change, output_api):
diff --git a/chrome/browser/resources/chromeos/arc_support/icon/playstore.svg b/chrome/browser/resources/chromeos/arc_support/icon/playstore.svg new file mode 100644 index 0000000..c725274 --- /dev/null +++ b/chrome/browser/resources/chromeos/arc_support/icon/playstore.svg
@@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <!-- Generator: Sketch 42 (36781) - http://www.bohemiancoding.com/sketch --> + <title>play_1x</title> + <desc>Created with Sketch.</desc> + <defs> + <linearGradient x1="91.4973431%" y1="4.9654308%" x2="-38.3351046%" y2="71.9100501%" id="linearGradient-1"> + <stop stop-color="#00A0FF" offset="0%"></stop> + <stop stop-color="#00A1FF" offset="0.6574452%"></stop> + <stop stop-color="#00BEFF" offset="26.01%"></stop> + <stop stop-color="#00D2FF" offset="51.22%"></stop> + <stop stop-color="#00DFFF" offset="76.04%"></stop> + <stop stop-color="#00E3FF" offset="100%"></stop> + </linearGradient> + <linearGradient x1="107.588641%" y1="49.995387%" x2="-130.472897%" y2="49.995387%" id="linearGradient-2"> + <stop stop-color="#FFE000" offset="0%"></stop> + <stop stop-color="#FFBD00" offset="40.87%"></stop> + <stop stop-color="#FFA500" offset="77.54%"></stop> + <stop stop-color="#FF9C00" offset="100%"></stop> + </linearGradient> + <linearGradient x1="86.243738%" y1="17.8461794%" x2="-50.1441583%" y2="194.807648%" id="linearGradient-3"> + <stop stop-color="#FF3A44" offset="0%"></stop> + <stop stop-color="#C31162" offset="100%"></stop> + </linearGradient> + <linearGradient x1="-18.8092486%" y1="-54.1510221%" x2="42.0933614%" y2="24.8694121%" id="linearGradient-4"> + <stop stop-color="#32A071" offset="0%"></stop> + <stop stop-color="#2DA771" offset="6.85%"></stop> + <stop stop-color="#15CF74" offset="47.62%"></stop> + <stop stop-color="#06E775" offset="80.09%"></stop> + <stop stop-color="#00F076" offset="100%"></stop> + </linearGradient> + </defs> + <g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <g id="play_1x"> + <g id="logo_play_prism_48dp"> + <g id="Group"> + <rect id="Rectangle-path" fill="#FFFFFF" opacity="0" x="0" y="0" width="32" height="32"></rect> + <g transform="translate(3.096774, 1.548387)" id="Shape"> + <path d="M0.517645344,0.607457627 C0.192688172,0.952010206 0,1.4843521 0,2.17672316 L0,26.8881648 C0,27.5805358 0.192688172,28.1145107 0.517645344,28.4574303 L0.600925825,28.5374449 L14.4434482,14.6965555 L14.4434482,14.5332604 L14.4434482,14.3699654 L0.599292874,0.525810097 L0.517645344,0.607457627 L0.517645344,0.607457627 Z" fill="url(#linearGradient-1)"></path> + <path d="M19.0565336,19.3129069 L14.4434482,14.6965555 L14.4434482,14.5332604 L14.4434482,14.3699654 L19.0581666,9.75524695 L19.1626754,9.81403317 L24.6297941,12.9199052 C26.1908948,13.8065974 26.1908948,15.2582905 24.6297941,16.1466156 L19.1626754,19.2524877 L19.0565336,19.3129069 L19.0565336,19.3129069 Z" fill="url(#linearGradient-2)"></path> + <path d="M19.1626754,19.2524877 L14.4434482,14.5332604 L0.517645344,28.4590632 C1.03202479,29.0044687 1.88279205,29.0714197 2.83970111,28.5276472 L19.1626754,19.2524877" fill="url(#linearGradient-3)"></path> + <path d="M19.1626754,9.81403317 L2.83970111,0.538873701 C1.88279205,-0.00489885183 1.03202479,0.0620521232 0.517645344,0.607457627 L14.4434482,14.5332604 L19.1626754,9.81403317 L19.1626754,9.81403317 Z" fill="url(#linearGradient-4)"></path> + <g transform="translate(0.000000, 19.105522)" fill="#000000"> + <path d="M19.0581666,0.0440896665 L2.83970111,9.25882996 C1.93178057,9.77484235 1.12183707,9.74055039 0.600925825,9.27026062 L0.600925825,9.27026062 L0.517645344,9.3535411 L0.517645344,9.3535411 L0.600925825,9.43355568 L0.600925825,9.43355568 C1.12183707,9.9022125 1.93178057,9.93813742 2.83970111,9.42212502 L19.1626754,0.146965555 L19.0581666,0.0440896665 L19.0581666,0.0440896665 Z" opacity="0.2"></path> + <path d="M0.517645344,9.19024604 C0.192688172,8.84569346 0,8.31171861 0,7.6209805 L0,7.78427556 C0,8.47664662 0.192688172,9.01062147 0.517645344,9.3535411 L0.600925825,9.27026062 L0.517645344,9.19024604 L0.517645344,9.19024604 Z" opacity="0.12"></path> + </g> + <path d="M24.6297941,15.9833206 L19.0581666,19.1496118 L19.1626754,19.2541206 L24.6297941,16.1482486 C25.4103445,15.704086 25.8006196,15.1194897 25.8006196,14.5348934 L25.8006196,14.5348934 C25.7353016,15.0623364 25.3368617,15.5816147 24.6297941,15.9833206 L24.6297941,15.9833206 Z" fill="#000000" opacity="0.12"></path> + <path d="M2.83970111,0.702168763 L24.6297941,13.0832003 C25.3384946,13.4849061 25.7353016,14.0041844 25.8006196,14.5332604 L25.8006196,14.5332604 C25.8006196,13.9486641 25.4103445,13.3640678 24.6297941,12.9199052 L2.83970111,0.538873701 C1.27696738,-0.34781848 0,0.388642245 0,2.17835611 L0,2.34165118 C0,0.551937306 1.27696738,-0.184523419 2.83970111,0.702168763 L2.83970111,0.702168763 Z" fill="#FFFFFF" opacity="0.25"></path> + </g> + </g> + </g> + </g> + </g> +</svg> \ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/arc_support/playstore.css b/chrome/browser/resources/chromeos/arc_support/playstore.css index 74f01ad..8c342c10 100644 --- a/chrome/browser/resources/chromeos/arc_support/playstore.css +++ b/chrome/browser/resources/chromeos/arc_support/playstore.css
@@ -2,11 +2,22 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ +a, +a:link, +a:visited { + color: rgb(51, 103, 214); + text-decoration: none; +} + body { margin: 0; padding: 8px 4px 8px 8px; } +body.large-view { + padding: 8px 16px 8px 20px; +} + ::-webkit-scrollbar { background: transparent; width: 4px; @@ -21,6 +32,24 @@ background: rgba(0, 0, 0, 0.2); } +.large-view .play-contained { + color: rgba(0, 0, 0, 0.87); + font-size: 13px; + line-height: 20px; +} + +.large-view .play-contained h2, +.large-view .play-contained strong { + color: rgba(0, 0, 0, 0.87); + font-size: 13px; + line-height: 20px; +} +.large-view .play-contained select { + color: rgba(0, 0, 0, 0.87); + font-size: 13px; + line-height: 20px; +} + .play-contained { color: rgba(0, 0, 0, 0.54); font-family: 'Roboto'; @@ -68,9 +97,3 @@ padding: 0; } -a, -a:link, -a:visited { - color: rgb(51, 103, 214); - text-decoration: none; -}
diff --git a/chrome/browser/resources/chromeos/arc_support/playstore.js b/chrome/browser/resources/chromeos/arc_support/playstore.js index f4b6bae..0593461 100644 --- a/chrome/browser/resources/chromeos/arc_support/playstore.js +++ b/chrome/browser/resources/chromeos/arc_support/playstore.js
@@ -89,6 +89,9 @@ * Formats current document in order to display it correctly. */ function formatDocument() { + if (document.viewMode) { + document.body.classList.add(document.viewMode); + } // playstore.css is injected into the document and it is applied first. // Need to remove existing links that contain references to external // stylesheets which override playstore.css.
diff --git a/chrome/browser/resources/chromeos/login/arc_terms_of_service.css b/chrome/browser/resources/chromeos/login/arc_terms_of_service.css new file mode 100644 index 0000000..9ea7407 --- /dev/null +++ b/chrome/browser/resources/chromeos/login/arc_terms_of_service.css
@@ -0,0 +1,90 @@ +/* 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. */ + +a { + color: var(--google-blue-500); + font-family: 'Roboto'; + font-size: 13px; + font-weight: 400; + text-decoration: none; +} + +p { + color: rgba(0, 0, 0, 0.54); + font-family: 'Roboto'; + font-size: 13px; + font-weight: 400; + line-height: 16px; + margin: 0; + padding: 0; +} + +.arc-tos-loaded .arc-tos-loading, +.arc-tos-loaded .arc-tos-error, +.arc-tos-loaded #arc-tos-retry-button-md, +.arc-tos-loading .arc-tos-content, +.arc-tos-loading .arc-tos-error, +.arc-tos-loading #arc-tos-retry-button-md, +.error .arc-tos-content, +.error .arc-tos-loading, +.error #arc-tos-accept-button-md { + display: none; +} + +.arc-tos-loading p, +.error p { + color: rgba(0, 0, 0, 0.87); + font-size: 16px; + font-weight: 400; + line-height: 20px; +} + +.parameter-section { + margin: 0; + max-width: 590px; + padding: 0 20px 16px 20px; +} + +#arc-enable-backup-restore-md, +#arc-enable-location-service-md { + --paper-checkbox-size: 12px; + --paper-checkbox-checked-color: rgb(66, 133, 244); /* #4285f4 */ + --paper-checkbox-label-spacing: 20px; + --paper-checkbox-vertical-align: top; +} + +#arc-policy-link-md { + margin: 0; + padding: 16px 0 16px 20px; +} + +#arc-tos-skip-button-md { + --oobe-text-button-border-color: rgba(0, 0, 0, 0.1); + color: rgba(0, 0, 0, 0.54); +} + +#arc-tos-view-md { + display: block; + height: 10px; + margin: auto; + padding: 0; +} + +#arc-tos-view-container-md { + border: 1px solid #d9d9d9; + box-sizing: border-box; + flex: auto; + margin: -4px 0 0 0; + padding: 0; + width: 100%; +} + +#arc-tos-skip-button-md { + -webkit-padding-end: 6px; +} + +#arc-tos-accept-button-md, +#arc-tos-retry-button-md { + -webkit-padding-end: 12px; +}
diff --git a/chrome/browser/resources/chromeos/login/arc_terms_of_service.html b/chrome/browser/resources/chromeos/login/arc_terms_of_service.html new file mode 100644 index 0000000..edd0b1c9 --- /dev/null +++ b/chrome/browser/resources/chromeos/login/arc_terms_of_service.html
@@ -0,0 +1,69 @@ +<!-- 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. --> + +<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-checkbox/paper-checkbox.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html"> + + +<dom-module name="arc-tos-md"> + <template> + <link rel="stylesheet" href="arc_terms_of_service.css"> + <link rel="stylesheet" href="oobe_dialog_parameters.css"> + <oobe-dialog id="arc-tos-dialog-md" class="arc-tos-loading" has-buttons> + <iron-icon src="chrome://oobe/playstore.svg" class="oobe-icon"> + </iron-icon> + <div class="header"> + <h1 class="title">$i18n{arcTermsOfServiceScreenHeading}</h1> + <div class="subtitle">$i18n{arcTermsOfServiceScreenDescription}</div> + </div> + <div class="footer flex layout vertical"> + <div id="arc-tos-view-container-md" class="arc-tos-content"> + <webview id="arc-tos-view-md"></webview> + </div> + <a id="arc-policy-link-md" class="arc-tos-content" href="#"> + $i18n{arcPolicyLink} + </a> + <div class="parameter-section arc-tos-content"> + <p id="arc-text-metrics-md"></p> + </div> + <div class="parameter-section arc-tos-content"> + <paper-checkbox id="arc-enable-backup-restore-md"> + <p i18n-values=".innerHTML:arcTextBackupRestore"></p> + </paper-checkbox> + </div> + <div class="parameter-section arc-tos-content"> + <paper-checkbox id="arc-enable-location-service-md"> + <p i18n-values=".innerHTML:arcTextLocationService"></p> + </paper-checkbox> + </div> + <div class="arc-tos-loading"> + <p>$i18n{arcTermsOfServiceLoading}</p> + </div> + <div class="arc-tos-error"> + <p>$i18n{arcTermsOfServiceError}</p> + </div> + </div> + <div class="bottom-buttons flex layout horizontal"> + <div class="flex"> + </div> + <oobe-text-button id="arc-tos-skip-button-md" on-tap="onSkip_" + disabled="[[arcTosButtonsDisabled]]"> + <div>$i18n{arcTermsOfServiceSkipButton}</div> + </oobe-text-button> + <oobe-text-button id="arc-tos-retry-button-md" + inverse on-tap="onRetry_" + disabled="[[arcTosButtonsDisabled]]"> + <div>$i18n{arcTermsOfServiceRetryButton}</div> + </oobe-text-button> + <oobe-text-button id="arc-tos-accept-button-md" + inverse on-tap="onAccept_" + disabled="[[arcTosButtonsDisabled]]"> + <div>$i18n{arcTermsOfServiceAcceptButton}</div> + </oobe-text-button> + </div> + </oobe-dialog> + </template> +</dom-module>
diff --git a/chrome/browser/resources/chromeos/login/arc_terms_of_service.js b/chrome/browser/resources/chromeos/login/arc_terms_of_service.js new file mode 100644 index 0000000..a4cce26 --- /dev/null +++ b/chrome/browser/resources/chromeos/login/arc_terms_of_service.js
@@ -0,0 +1,64 @@ +// 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. + +/** + * @fileoverview Polymer element for displaying material design for ARC Terms Of + * Service screen. + */ + +Polymer({ + is: 'arc-tos-md', + + properties: { + /** + * Accept, Skip and Retry buttons are disabled until content is loaded. + */ + arcTosButtonsDisabled: { + type: Boolean, + value: true, + }, + + /** + * Reference to OOBE screen object. + * @type {!OobeTypes.Screen} + */ + screen: { + type: Object, + }, + }, + + /** + * Returns element by its id. + */ + getElement: function(id) { + return this.$[id]; + }, + + /** + * On-tap event handler for Accept button. + * + * @private + */ + onAccept_ : function() { + this.screen.onAccept(); + }, + + /** + * On-tap event handler for Retry button. + * + * @private + */ + onRetry_ : function() { + this.screen.reloadPlayStore(); + }, + + /** + * On-tap event handler for Skip button. + * + * @private + */ + onSkip_ : function() { + this.screen.onSkip(); + } +});
diff --git a/chrome/browser/resources/chromeos/login/custom_elements_login.html b/chrome/browser/resources/chromeos/login/custom_elements_login.html index a4551a9..cd7fb8b8 100644 --- a/chrome/browser/resources/chromeos/login/custom_elements_login.html +++ b/chrome/browser/resources/chromeos/login/custom_elements_login.html
@@ -13,5 +13,8 @@ <include src="unrecoverable_cryptohome_error_card.html"> <include src="offline_ad_login.html"> <include src="active_directory_password_change.html"> +<include src="arc_terms_of_service.html"> +<include src="oobe_buttons.html"> +<include src="oobe_dialog.html"> <script src="chrome://oobe/custom_elements.js"></script>
diff --git a/chrome/browser/resources/chromeos/login/custom_elements_login.js b/chrome/browser/resources/chromeos/login/custom_elements_login.js index 3b04fc93..77c718c 100644 --- a/chrome/browser/resources/chromeos/login/custom_elements_login.js +++ b/chrome/browser/resources/chromeos/login/custom_elements_login.js
@@ -17,3 +17,6 @@ // <include src="unrecoverable_cryptohome_error_card.js"> // <include src="offline_ad_login.js"> // <include src="active_directory_password_change.js"> +// <include src="oobe_buttons.js"> +// <include src="oobe_dialog.js"> +// <include src="arc_terms_of_service.js">
diff --git a/chrome/browser/resources/chromeos/login/custom_elements_oobe.html b/chrome/browser/resources/chromeos/login/custom_elements_oobe.html index 112bb89..c7d4b46a 100644 --- a/chrome/browser/resources/chromeos/login/custom_elements_oobe.html +++ b/chrome/browser/resources/chromeos/login/custom_elements_oobe.html
@@ -25,5 +25,6 @@ <include src="oobe_welcome.html"> <include src="offline_ad_login.html"> <include src="active_directory_password_change.html"> +<include src="arc_terms_of_service.html"> <script src="chrome://oobe/custom_elements.js"></script>
diff --git a/chrome/browser/resources/chromeos/login/custom_elements_oobe.js b/chrome/browser/resources/chromeos/login/custom_elements_oobe.js index ab6875f..10206724 100644 --- a/chrome/browser/resources/chromeos/login/custom_elements_oobe.js +++ b/chrome/browser/resources/chromeos/login/custom_elements_oobe.js
@@ -35,3 +35,4 @@ // <include src="oobe_welcome.js"> // <include src="offline_ad_login.js"> // <include src="active_directory_password_change.js"> +// <include src="arc_terms_of_service.js">
diff --git a/chrome/browser/resources/chromeos/login/oobe_buttons.html b/chrome/browser/resources/chromeos/login/oobe_buttons.html index 658b7fc..1455522 100644 --- a/chrome/browser/resources/chromeos/login/oobe_buttons.html +++ b/chrome/browser/resources/chromeos/login/oobe_buttons.html
@@ -15,6 +15,10 @@ <path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"> </path> </g> + <g id="arrow-forward"> + <path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"> + </path> + </g> </defs> </svg> </iron-iconset-svg> @@ -27,7 +31,7 @@ Example: <oobe-icon-button inverse> - <div>$i18n{oobeOKButtonText}</div> + <div>OK</div> </oobe-icon-button> Attributes: @@ -48,7 +52,7 @@ </dom-module> <!-- - Material design square "<- Back" button. + Material design square "<- Back" and "Next ->" buttons. Text is blue, background is white. Example: @@ -59,7 +63,7 @@ 'disabled' - button is disabled when the attribute is set. --> <dom-module id="oobe-back-button"> - <link rel="stylesheet" href="oobe_back_button.css"> + <link rel="stylesheet" href="oobe_nav_button.css"> <template> <paper-button id="button" on-tap="onClick_" disabled="[[disabled]]"> <div class="flex horizontal layout start center"> @@ -70,6 +74,18 @@ </template> </dom-module> +<dom-module id="oobe-next-button"> + <link rel="stylesheet" href="oobe_nav_button.css"> + <template> + <paper-button id="button" on-tap="onClick_" disabled="[[disabled]]"> + <div class="flex horizontal layout start center"> + <div id="text">$i18n{next}</div> + <iron-icon icon="oobe-buttons:arrow-forward"></iron-icon> + </div> + </paper-button> + </template> +</dom-module> + <!-- Material design button that shows an icon and displays text.
diff --git a/chrome/browser/resources/chromeos/login/oobe_buttons.js b/chrome/browser/resources/chromeos/login/oobe_buttons.js index b032445..68650e3 100644 --- a/chrome/browser/resources/chromeos/login/oobe_buttons.js +++ b/chrome/browser/resources/chromeos/login/oobe_buttons.js
@@ -39,6 +39,23 @@ }); Polymer({ + is: 'oobe-next-button', + + properties: { + disabled: {type: Boolean, value: false, reflectToAttribute: true}, + }, + + focus: function() { + this.$.button.focus(); + }, + + onClick_: function(e) { + if (this.disabled) + e.stopPropagation(); + } +}); + +Polymer({ is: 'oobe-welcome-secondary-button', properties: {
diff --git a/chrome/browser/resources/chromeos/login/oobe_dialog.html b/chrome/browser/resources/chromeos/login/oobe_dialog.html index 10d4e67..628d8e143 100644 --- a/chrome/browser/resources/chromeos/login/oobe_dialog.html +++ b/chrome/browser/resources/chromeos/login/oobe_dialog.html
@@ -16,7 +16,7 @@ <oobe-dialog has-buttons> <iron-icon ... class="oobe-icon"> <div class="header"> - <h1> class="title">Title</h1> + <h1 class="title">Title</h1> <div class="subtitle">Subtitle</div> </div> <div class="footer">
diff --git a/chrome/browser/resources/chromeos/login/oobe_back_button.css b/chrome/browser/resources/chromeos/login/oobe_nav_button.css similarity index 89% rename from chrome/browser/resources/chromeos/login/oobe_back_button.css rename to chrome/browser/resources/chromeos/login/oobe_nav_button.css index 341760e..59d7f8cb 100644 --- a/chrome/browser/resources/chromeos/login/oobe_back_button.css +++ b/chrome/browser/resources/chromeos/login/oobe_nav_button.css
@@ -15,7 +15,7 @@ height: 32px; /* = 28 + border (2px + 2px) */ margin: 0; min-width: 92px; /* = 88 + border (2px + 2px) */ - padding: 0; + padding: 0 16px; } #button:not([focused]) { @@ -26,15 +26,13 @@ } #text { - -webkit-padding-end: 16px; text-transform: none; } iron-icon { --iron-icon-height: 12px; --iron-icon-width: 12px; - -webkit-padding-end: 8px; - -webkit-padding-start: 16px; + padding: 0 8px; } #button[disabled] #text, @@ -42,3 +40,6 @@ color: rgba(0, 0, 0, 0.34); } +paper-button[disabled] { + background: transparent; +}
diff --git a/chrome/browser/resources/chromeos/login/oobe_next_button.css b/chrome/browser/resources/chromeos/login/oobe_next_button.css deleted file mode 100644 index f4ddcdb1..0000000 --- a/chrome/browser/resources/chromeos/login/oobe_next_button.css +++ /dev/null
@@ -1,12 +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. */ - -:host { - display: inline-block; -} -paper-fab { - background-color: var(--google-blue-500); - color: white; - font-size: 14px; -}
diff --git a/chrome/browser/resources/chromeos/login/oobe_text_button.css b/chrome/browser/resources/chromeos/login/oobe_text_button.css index 4febed4..9db05c4 100644 --- a/chrome/browser/resources/chromeos/login/oobe_text_button.css +++ b/chrome/browser/resources/chromeos/login/oobe_text_button.css
@@ -15,7 +15,7 @@ } #textButton:not([focused]) { - border-color: transparent; + border-color: var(--oobe-text-button-border-color, transparent); border-radius: 2px; border-style: solid; border-width: 2px;
diff --git a/chrome/browser/resources/chromeos/login/oobe_welcome.css b/chrome/browser/resources/chromeos/login/oobe_welcome.css index 45b61aac..03484304 100644 --- a/chrome/browser/resources/chromeos/login/oobe_welcome.css +++ b/chrome/browser/resources/chromeos/login/oobe_welcome.css
@@ -38,8 +38,7 @@ /************* Network Selection Screen **************/ #networkSelectionScreen .footer { - margin-bottom: 10px; - max-height: 297px; + max-height: 313px; } #networkSelectionScreen .bottom-buttons {
diff --git a/chrome/browser/resources/chromeos/login/oobe_welcome.html b/chrome/browser/resources/chromeos/login/oobe_welcome.html index 69d0282..5ab6782 100644 --- a/chrome/browser/resources/chromeos/login/oobe_welcome.html +++ b/chrome/browser/resources/chromeos/login/oobe_welcome.html
@@ -184,15 +184,19 @@ </div> <div class="footer layout vertical"> <cr-network-select id="networkSelect" - on-network-connected="onNetworkConnected_" + on-default-network-changed="onDefaultNetworkChanged_" on-network-item-selected="onNetworkListNetworkItemSelected_" on-custom-item-selected="onNetworkListCustomItemSelected_" - custom-items="[[_getNetworkCustomItems()]]"> + custom-items="[[_getNetworkCustomItems()]]" + no-bottom-scroll-border> </cr-network-select> </div> - <div class="bottom-buttons layout horizontal start-justified"> + <div class="bottom-buttons layout horizontal justified"> <oobe-back-button on-tap="onNetworkSelectionBackButtonPressed_"> </oobe-back-button> + <oobe-next-button disabled="[[!isConnected_]]" + on-tap="onSelectedNetworkConnected_"> + </oobe-next-button> </div> </oobe-dialog> </template>
diff --git a/chrome/browser/resources/chromeos/login/oobe_welcome.js b/chrome/browser/resources/chromeos/login/oobe_welcome.js index 3ccc487..434a096 100644 --- a/chrome/browser/resources/chromeos/login/oobe_welcome.js +++ b/chrome/browser/resources/chromeos/login/oobe_welcome.js
@@ -107,6 +107,15 @@ type: String, value: '', }, + + /** + * True when connected to a network. + * @private + */ + isConnected_: { + type: Boolean, + value: false, + } }, /** @override */ @@ -296,14 +305,15 @@ }, /** - * This gets called when a network enters the 'Connected' state. - * - * @param {!{detail: !CrOnc.NetworkStateProperties}} event + * This gets called whenever the default network changes. + * @param {!{detail: ?CrOnc.NetworkStateProperties}} event * @private */ - onNetworkConnected_: function(event) { + onDefaultNetworkChanged_: function(event) { var state = event.detail; - if (state.GUID != this.networkLastSelectedGuid_) + this.isConnected_ = + !!state && state.ConnectionState == CrOnc.ConnectionState.CONNECTED; + if (!state || state.GUID != this.networkLastSelectedGuid_) return; // Duplicate asynchronous event may be delivered to some other screen,
diff --git a/chrome/browser/resources/chromeos/login/screen_active_directory_password_change.js b/chrome/browser/resources/chromeos/login/screen_active_directory_password_change.js index ec04944..391efad 100644 --- a/chrome/browser/resources/chromeos/login/screen_active_directory_password_change.js +++ b/chrome/browser/resources/chromeos/login/screen_active_directory_password_change.js
@@ -41,9 +41,9 @@ * @param {string} username Name of user that should change the password. */ show: function(username) { - // We'll get here after the successful Active Directory authentication. - // It assumes session is about to start so hides login screen controls. - Oobe.getInstance().headerHidden = true; + // Active Directory password change screen is similar to Active Directory + // login screen. So we restore bottom bar controls. + Oobe.getInstance().headerHidden = false; Oobe.showScreen({id: SCREEN_ACTIVE_DIRECTORY_PASSWORD_CHANGE}); this.adPasswordChanged_.reset(); this.adPasswordChanged_.username = username;
diff --git a/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.css b/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.css index 78224c2..e301488 100644 --- a/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.css +++ b/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.css
@@ -2,10 +2,15 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ -#arc-tos { +#arc-tos:not([md-mode]) { padding: 16px 17px 21px; } +#arc-tos[md-mode] { + min-height: unset; + padding: unset; +} + #arc-tos .step-contents { -webkit-margin-start: 32px; margin-bottom: 49px; @@ -125,7 +130,8 @@ #arc-tos-overlay-content-text p { color: rgba(0, 0, 0, 0.54); - font-size: 12px; + font-family: 'Roboto'; + font-size: 10px; font-weight: 400; text-align: justify; } @@ -205,3 +211,9 @@ .arc-tos-overlay-close-up:active { background-image: url(chrome://theme/IDR_CLOSE_DIALOG_P); } + +#arc-tos[md-mode] #arc-tos-overlay-content-text p { + color: rgba(0, 0, 0, 0.87); + font-size: 13px; +} +
diff --git a/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.html b/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.html index 0f46abc..dc44d2f 100644 --- a/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.html +++ b/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.html
@@ -1,40 +1,44 @@ <link rel="stylesheet" href="chrome://resources/css/overlay.css"> -<div class="step right hidden arc-tos-loading no-logo" id="arc-tos" hidden> - <div class="step-contents"> - <img id="arc-tos-logo" - src="https://play.google.com/about/images/play_logo.png" alt> - <h1>$i18n{arcTermsOfServiceScreenHeading}</h1> - <h2>$i18n{arcTermsOfServiceScreenDescription}</h2> - <div id="arc-tos-container"> - <div id="arc-tos-content"> - <div id="arc-tos-view-container"> - <webview id="arc-tos-view"></webview> +<div class="step right hidden arc-tos-loading no-logo" id="arc-tos" + role="group" hidden> + <arc-tos-md id="arc-tos-md" hidden></arc-tos-md> + <div id="arc-tos-legacy"> + <div class="step-contents"> + <img id="arc-tos-logo" + src="https://play.google.com/about/images/play_logo.png" alt> + <h1>$i18n{arcTermsOfServiceScreenHeading}</h1> + <h2>$i18n{arcTermsOfServiceScreenDescription}</h2> + <div id="arc-tos-container"> + <div id="arc-tos-content"> + <div id="arc-tos-view-container"> + <webview id="arc-tos-view"></webview> + </div> + <label> + <a id="arc-policy-link" href="#">$i18n{arcPolicyLink}</a> + </label> + <label> + <p id="arc-text-metrics"></p> + </label> + <label> + <input type="checkbox" id="arc-enable-backup-restore"> + <p i18n-values=".innerHTML:arcTextBackupRestore"></p> + </label> + <label> + <input type="checkbox" id="arc-enable-location-service"> + <p i18n-values=".innerHTML:arcTextLocationService"></p> + </label> </div> - <label> - <a id="arc-policy-link" href="#">$i18n{arcPolicyLink}</a> - </label> - <label> - <p id="arc-text-metrics"></p> - </label> - <label> - <input type="checkbox" id="arc-enable-backup-restore"> - <p i18n-values=".innerHTML:arcTextBackupRestore"></p> - </label> - <label> - <input type="checkbox" id="arc-enable-location-service"> - <p i18n-values=".innerHTML:arcTextLocationService"></p> - </label> - </div> - <div id="arc-tos-loading"> - <p>$i18n{arcTermsOfServiceLoading}</p> - </div> - <div id="arc-tos-error"> - <p>$i18n{arcTermsOfServiceError}</p> + <div id="arc-tos-loading"> + <p>$i18n{arcTermsOfServiceLoading}</p> + </div> + <div id="arc-tos-error"> + <p>$i18n{arcTermsOfServiceError}</p> + </div> </div> </div> + <div id="arc-tos-controls" class="step-controls"></div> </div> - <div id="arc-tos-controls" class="step-controls"></div> <div id="arc-tos-overlay-text" class="popup-overlay" hidden> <div class="oobe-popup not-resizable">
diff --git a/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.js b/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.js index a33f9cf..1b5f4c1e 100644 --- a/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.js +++ b/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.js
@@ -17,12 +17,37 @@ /** @override */ decorate: function(element) { + // Valid newOobeUI is not available at this time. + }, + + /** + * Makes sure that UI is initialized and MD mode is correctly set. + * + * @private + */ + setMDMode_: function() { + var useMDOobe = (loadTimeData.getString('newOobeUI') == 'on'); + if (typeof this.useMDOobe !== 'undefined' && + this.useMDOobe == useMDOobe) { + return; + } + + this.useMDOobe = useMDOobe; + $('arc-tos-md').screen = this; + $('arc-tos-md').hidden = !this.useMDOobe; + $('arc-tos-legacy').hidden = this.useMDOobe; + if (this.useMDOobe) { + $('arc-tos').setAttribute('md-mode', 'true'); + } else { + $('arc-tos').removeAttribute('md-mode'); + } + var closeButtons = document.querySelectorAll('.arc-overlay-close-button'); for (var i = 0; i < closeButtons.length; i++) { closeButtons[i].addEventListener('click', this.hideOverlay.bind(this)); } - var termsView = $('arc-tos-view'); + var termsView = this.getElement_('arc-tos-view'); var requestFilter = { urls: ['<all_urls>'], types: ['main_frame'] @@ -48,7 +73,7 @@ run_at: 'document_end' }]); - $('arc-policy-link').onclick = function() { + this.getElement_('arc-policy-link').onclick = function() { termsView.executeScript( {code: 'getPrivacyPolicyLink();'}, function(results) { @@ -60,8 +85,6 @@ } }); }; - - this.updateLocalizedContent(); }, /** @@ -70,8 +93,10 @@ * @param {boolean} visible If metrics text is visible. */ setMetricsMode: function(text, visible) { - $('arc-text-metrics').hidden = !visible; - $('arc-text-metrics').innerHTML = text; + var metrics = this.getElement_('arc-text-metrics'); + metrics.innerHTML = text; + // This element is wrapped by label in legacy mode and by div in MD mode. + metrics.parentElement.hidden = !visible; if (!visible) { return; @@ -80,7 +105,7 @@ var self = this; var leanMoreStatisticsText = loadTimeData.getString('arcLearnMoreStatistics'); - $('learn-more-link-metrics').onclick = function() { + metrics.querySelector('#learn-more-link-metrics').onclick = function() { self.showLearnMoreOverlay(leanMoreStatisticsText); }; }, @@ -88,14 +113,14 @@ /** * Applies current enabled/managed state to checkbox and text. * @param {string} checkBoxId Id of checkbox to set on/off. - * @param {string} textId Id of text to set enabled state. * @param {boolean} enabled Defines the value of the checkbox. * @param {boolean} managed Defines whether this setting is set by policy. */ - setPreference(checkBoxId, textId, enabled, managed) { - $(checkBoxId).checked = enabled; - $(checkBoxId).disabled = managed; - $(textId).disabled = managed; + setPreference(checkBoxId, enabled, managed) { + var preference = this.getElement_(checkBoxId); + preference.checked = enabled; + preference.disabled = managed; + preference.parentElement.disabled = managed; }, /** @@ -106,7 +131,6 @@ */ setBackupAndRestoreMode: function(enabled, managed) { this.setPreference('arc-enable-backup-restore', - 'arc-text-backup-restore', enabled, managed); }, @@ -117,7 +141,6 @@ */ setLocationServicesMode: function(enabled, managed) { this.setPreference('arc-enable-location-service', - 'arc-text-location-service', enabled, managed); }, @@ -126,14 +149,17 @@ * @param {string} countryCode Country code based on current timezone. */ setCountryCode: function(countryCode) { - var scriptSetCountryCode = 'document.countryCode = \'' + + var scriptSetParameters = 'document.countryCode = \'' + countryCode.toLowerCase() + '\';'; - var termsView = $('arc-tos-view'); + if (this.useMDOobe) { + scriptSetParameters += 'document.viewMode = \'large-view\';'; + } + var termsView = this.getElement_('arc-tos-view'); termsView.removeContentScripts(['preProcess']); termsView.addContentScripts([ { name: 'preProcess', matches: ['https://play.google.com/*'], - js: { code: scriptSetCountryCode }, + js: { code: scriptSetParameters }, run_at: 'document_start' }]); @@ -155,11 +181,7 @@ skipButton.classList.add('preserve-disabled-state'); skipButton.textContent = loadTimeData.getString('arcTermsOfServiceSkipButton'); - skipButton.addEventListener('click', function(event) { - $('arc-tos-skip-button').disabled = true; - $('arc-tos-accept-button').disabled = true; - chrome.send('arcTermsOfServiceSkip'); - }); + skipButton.addEventListener('click', this.onSkip.bind(this)); buttons.push(skipButton); var retryButton = this.ownerDocument.createElement('button'); @@ -175,22 +197,50 @@ acceptButton.classList.add('preserve-disabled-state'); acceptButton.textContent = loadTimeData.getString('arcTermsOfServiceAcceptButton'); - acceptButton.addEventListener('click', function(event) { - $('arc-tos-skip-button').disabled = true; - $('arc-tos-accept-button').disabled = true; - - var isBackupRestoreEnabled = $('arc-enable-backup-restore').checked; - var isLocationServiceEnabled = $('arc-enable-location-service').checked; - - chrome.send('arcTermsOfServiceAccept', - [isBackupRestoreEnabled, isLocationServiceEnabled]); - }); + acceptButton.addEventListener('click', this.onAccept.bind(this)); buttons.push(acceptButton); return buttons; }, /** + * Handles Accept button click. + */ + onAccept: function() { + this.enableButtons_(false); + + var isBackupRestoreEnabled = + this.getElement_('arc-enable-backup-restore').checked; + var isLocationServiceEnabled = + this.getElement_('arc-enable-location-service').checked; + + chrome.send('arcTermsOfServiceAccept', + [isBackupRestoreEnabled, isLocationServiceEnabled]); + }, + + /** + * Handles Retry button click. + */ + onSkip: function() { + this.enableButtons_(false); + + chrome.send('arcTermsOfServiceSkip'); + }, + + /** + * Enables/Disables set of buttons: Accept, Skip, Retry. + * @param {boolean} enable Buttons are enabled if set to true. + * + * @private + */ + enableButtons_: function(enable) { + $('arc-tos-skip-button').disabled = !enable; + $('arc-tos-accept-button').disabled = !enable; + $('arc-tos-retry-button').disabled = !enable; + $('arc-tos-md').arcTosButtonsDisabled = !enable; + }, + + /** * Returns the control which should receive initial focus. */ get defaultControl() { @@ -230,14 +280,37 @@ */ reloadPlayStore: function() { this.termsError = false; - var termsView = $('arc-tos-view'); + var termsView = this.getElement_('arc-tos-view'); termsView.src = 'https://play.google.com/about/play-terms.html'; - this.classList.remove('arc-tos-loaded'); - this.classList.remove('error'); - this.classList.add('arc-tos-loading'); + this.removeClass_('arc-tos-loaded'); + this.removeClass_('error'); + this.addClass_('arc-tos-loading'); + this.enableButtons_(false); + }, - $('arc-tos-accept-button').disabled = true; - $('arc-tos-skip-button').disabled = true; + /** + * Adds new class to the list of classes of root OOBE MD style and legacy + * style root elements. + * @param {string} className class to remove. + * + * @private + */ + addClass_: function (className) { + this.classList.add(className); + $('arc-tos-md').getElement('arc-tos-dialog-md').classList.add(className); + }, + + /** + * Removes class from the list of classes of root OOBE MD style and legacy + * style root elements. + * @param {string} className class to remove. + * + * @private + */ + removeClass_: function (className) { + this.classList.remove(className); + $('arc-tos-md').getElement('arc-tos-dialog-md').classList. + remove(className); }, /** @@ -248,19 +321,15 @@ return; } - this.classList.remove('arc-tos-loading'); - this.classList.remove('error'); - this.classList.add('arc-tos-loaded'); + this.removeClass_('arc-tos-loading'); + this.removeClass_('error'); + this.addClass_('arc-tos-loaded'); - var acceptButton = $('arc-tos-accept-button'); - var skipButton = $('arc-tos-skip-button'); + this.enableButtons_(true); + this.getElement_('arc-tos-accept-button').focus(); - skipButton.disabled = false; - acceptButton.disabled = false; - acceptButton.focus(); - - var termsView = $('arc-tos-view'); - var termsViewContainer = $('arc-tos-view-container'); + var termsView = this.getElement_('arc-tos-view'); + var termsViewContainer = this.getElement_('arc-tos-view-container'); var setTermsHeight = function() { // Reset terms-view height in order to stabilize style computation. // For some reason, child webview affects final result. @@ -277,9 +346,9 @@ */ onTermsViewErrorOccurred: function(details) { this.termsError = true; - this.classList.remove('arc-tos-loading'); - this.classList.remove('arc-tos-loaded'); - this.classList.add('error'); + this.removeClass_('arc-tos-loading'); + this.removeClass_('arc-tos-loaded'); + this.addClass_('error'); $('arc-tos-retry-button').focus(); }, @@ -289,6 +358,9 @@ * @param {object} data Screen init payload. */ onBeforeShow: function(data) { + this.setMDMode_(); + this.setLearnMoreHandlers_(); + Oobe.getInstance().headerHidden = true; // Reload caption image in case it was not loaded during the @@ -301,20 +373,51 @@ }, /** + * Returns requested element from related part of HTML determined by current + * MD OOBE mode. + * @param {string} id Id of an element to find. + * + * @private + */ + getElement_: function(id) { + if (this.useMDOobe) { + return $('arc-tos-md').getElement(id + '-md'); + } + return $(id); + }, + + /** * Updates localized content of the screen that is not updated via template. */ updateLocalizedContent: function() { + this.setMDMode_(); + this.setLearnMoreHandlers_(); + }, + + /** + * Sets handlers for learn more links for backup and restore and location + * service options. + * + * @private + */ + setLearnMoreHandlers_: function() { var self = this; var leanMoreBackupAndRestoreText = loadTimeData.getString('arcLearnMoreBackupAndRestore'); - $('learn-more-link-backup-restore').onclick = function() { + var backupAndRestore = this.getElement_('arc-enable-backup-restore'); + backupAndRestore.parentElement.querySelector( + '#learn-more-link-backup-restore').onclick = function(event) { + event.stopPropagation(); self.showLearnMoreOverlay(leanMoreBackupAndRestoreText); }; var leanMoreLocationServiceText = loadTimeData.getString('arcLearnMoreLocationService'); - $('learn-more-link-location-service').onclick = function() { + var locationService = this.getElement_('arc-enable-location-service'); + locationService.parentElement.querySelector( + '#learn-more-link-location-service').onclick = function(event) { + event.stopPropagation(); self.showLearnMoreOverlay(leanMoreLocationServiceText); }; }
diff --git a/chrome/browser/resources/chromeos/login/screen_container.html b/chrome/browser/resources/chromeos/login/screen_container.html index f258aa4..09caa38a 100644 --- a/chrome/browser/resources/chromeos/login/screen_container.html +++ b/chrome/browser/resources/chromeos/login/screen_container.html
@@ -1,5 +1,4 @@ <div id="background" class="background-initial"></div> -<include src="version.html"> <include src="api_keys_notice.html"> <div id="scroll-container"> <div id="outer-container" class="down"> @@ -18,6 +17,7 @@ </div> </div> <div id="bubble" class="bubble faded" hidden></div> +<include src="version.html"> <include src="header_bar.html"> <include src="../../../../../ui/login/account_picker/user_pod_template.html"> <include src="oobe_screen_reset_confirmation_overlay.html">
diff --git a/chrome/browser/resources/component_extension_resources.grd b/chrome/browser/resources/component_extension_resources.grd index 2cec82f..07fffad 100644 --- a/chrome/browser/resources/component_extension_resources.grd +++ b/chrome/browser/resources/component_extension_resources.grd
@@ -153,6 +153,7 @@ <include name="IDR_ARC_SUPPORT_LSO_CSS" file="chromeos/arc_support/lso.css" type="BINDATA" /> <include name="IDR_ARC_SUPPORT_PLAYSTORE_CSS" file="chromeos/arc_support/playstore.css" type="BINDATA" /> <include name="IDR_ARC_SUPPORT_PLAYSTORE_JS" file="chromeos/arc_support/playstore.js" type="BINDATA" /> + <include name="IDR_ARC_SUPPORT_PLAYSTORE_LOGO" file="chromeos/arc_support/icon/playstore.svg" type="BINDATA" /> <include name="IDR_ARC_SUPPORT_MAIN" file="chromeos/arc_support/main.html" allowexternalscript="true" type="BINDATA" /> <include name="IDR_ARC_SUPPORT_ICON_48" file="chromeos/arc_support/icon/48.png" type="BINDATA" /> <include name="IDR_ARC_SUPPORT_ICON_96" file="chromeos/arc_support/icon/96.png" type="BINDATA" />
diff --git a/chrome/browser/resources/md_bookmarks/item.js b/chrome/browser/resources/md_bookmarks/item.js index 3f8c87f5..b75eb60 100644 --- a/chrome/browser/resources/md_bookmarks/item.js +++ b/chrome/browser/resources/md_bookmarks/item.js
@@ -63,7 +63,10 @@ * @private */ onDblClick_: function(e) { - /* TODO(jiaxi): Add double click later. */ + if (!this.item.url) + this.fire('selected-folder-changed', this.item.id); + else + chrome.tabs.create({url: this.item.url}); }, /**
diff --git a/chrome/browser/resources/md_bookmarks/store.js b/chrome/browser/resources/md_bookmarks/store.js index 8f0ef849..eb4cb11 100644 --- a/chrome/browser/resources/md_bookmarks/store.js +++ b/chrome/browser/resources/md_bookmarks/store.js
@@ -357,9 +357,24 @@ if (!this.idToNodeMap_[id] || this.idToNodeMap_[id].url) id = this.rootNode.children[0].id; - var newFolder = this.idToNodeMap_[id]; - this.set(newFolder.path + '.isSelectedFolder', true); + var folder = this.idToNodeMap_[id]; + this.set(folder.path + '.isSelectedFolder', true); this.selectedId = id; + + if (folder.id == this.rootNode.id) + return; + + var parent = this.idToNodeMap_[/** @type {?string} */ (folder.parentId)]; + while (parent) { + if (!parent.isOpen) { + this.fire('folder-open-changed', { + id: parent.id, + open: true, + }); + } + + parent = this.idToNodeMap_[/** @type {?string} */ (parent.parentId)]; + } }, /**
diff --git a/chrome/browser/resources/md_downloads/BUILD.gn b/chrome/browser/resources/md_downloads/BUILD.gn index c10d231b..b852bd4 100644 --- a/chrome/browser/resources/md_downloads/BUILD.gn +++ b/chrome/browser/resources/md_downloads/BUILD.gn
@@ -1,13 +1,11 @@ import("../vulcanize.gni") vulcanize("vulcanize") { + deps = [] host = "downloads" html_in_file = "downloads.html" html_out_file = "vulcanized.html" - insert_in_head = "<base href=chrome://downloads>" - - input_type = "FOLDER" input = rebase_path(".", root_build_dir) + insert_in_head = "<base href=chrome://downloads>" js_out_file = "crisper.js" - deps = [] }
diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js index 96283c3d..b4dbd5c 100644 --- a/chrome/browser/resources/options/browser_options.js +++ b/chrome/browser/resources/options/browser_options.js
@@ -339,12 +339,10 @@ // Device section (ChromeOS only). if (cr.isChromeOS) { - if (loadTimeData.getBoolean('showStylusSettings')) { - $('stylus-settings-link').onclick = function(event) { - PageManager.showPageByName('stylus-overlay'); - }; - $('stylus-row').hidden = false; - } + // Probe for stylus hardware state. C++ will invoke + // BrowserOptions.setStylusInputStatus_ when the data is available. + chrome.send('requestStylusHardwareState'); + if (loadTimeData.getBoolean('showPowerStatus')) { $('power-settings-link').onclick = function(evt) { PageManager.showPageByName('power-overlay'); @@ -1814,6 +1812,21 @@ }, /** + * Called when stylus hardware detection probing is complete. + * @param {boolean} hasStylus + * @private + */ + setStylusInputStatus_: function(hasStylus) { + if (!hasStylus) + return; + + $('stylus-settings-link').onclick = function(event) { + PageManager.showPageByName('stylus-overlay'); + }; + $('stylus-row').hidden = false; + }, + + /** * This is called from chromium code when system timezone "managed" state * is changed. Enables or disables dependent settings. * @param {boolean} managed Is true when system Timezone is managed by @@ -2412,6 +2425,7 @@ 'setNowSectionVisible', 'setProfilesInfo', 'setSpokenFeedbackCheckboxState', + 'setStylusInputStatus', 'setSystemTimezoneAutomaticDetectionManaged', 'setSystemTimezoneManaged', 'setThemesResetButtonEnabled',
diff --git a/chrome/browser/resources/password_manager_internals/OWNERS b/chrome/browser/resources/password_manager_internals/OWNERS index 5296ea4..e8e1954b 100644 --- a/chrome/browser/resources/password_manager_internals/OWNERS +++ b/chrome/browser/resources/password_manager_internals/OWNERS
@@ -1,2 +1,4 @@ mkwst@chromium.org vabr@chromium.org + +# COMPONENT: UI>Browser>Passwords
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.html b/chrome/browser/resources/settings/basic_page/basic_page.html index d56f44b1..7f75d71 100644 --- a/chrome/browser/resources/settings/basic_page/basic_page.html +++ b/chrome/browser/resources/settings/basic_page/basic_page.html
@@ -1,6 +1,7 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="../a11y_page/a11y_page.html"> <link rel="import" href="../appearance_page/appearance_page.html"> +<link rel="import" href="../controls/settings_idle_render.html"> <link rel="import" href="../downloads_page/downloads_page.html"> <link rel="import" href="../languages_page/languages_page.html"> <link rel="import" href="../on_startup_page/on_startup_page.html"> @@ -114,7 +115,8 @@ </template> </if> <template is="dom-if" if="[[showPage(pageVisibility.search)]]" restamp> - <settings-section page-title="$i18n{searchPageTitle}" section="search"> + <settings-section page-title="$i18n{searchPageTitle}" + section="search"> <settings-search-page prefs="{{prefs}}"></settings-search-page> </settings-section> </template> @@ -148,8 +150,7 @@ </div> </template> - <template is="dom-if" - if="[[showAdvancedSettings_(pageVisibility.advancedSettings)]]"> + <div hidden$="[[!showAdvancedSettings_(pageVisibility.advancedSettings)]]"> <template is="dom-if" if="[[showAdvancedToggle_( inSearchMode, hasExpandedSection_)]]"> <div id="toggleSpacer"></div> @@ -163,10 +164,10 @@ </h2> </template> - <template is="dom-if" if="[[showAdvancedPage_( - currentRoute_, inSearchMode, hasExpandedSection_, - advancedToggleExpanded)]]"> - <div id="advancedPage"> + <template is="settings-idle-render" id="advancedPageTemplate"> + <div id="advancedPage" hidden$="[[!showAdvancedPage_( + currentRoute_, inSearchMode, hasExpandedSection_, + advancedToggleExpanded)]]"> <if expr="chromeos"> <template is="dom-if" if="[[showPage(pageVisibility.dateTime)]]" restamp> @@ -244,7 +245,7 @@ </template> </div> </template> - </template> + </div> </template> <script src="basic_page.js"></script> </dom-module>
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.js b/chrome/browser/resources/settings/basic_page/basic_page.js index bc14ed22..82e9add5 100644 --- a/chrome/browser/resources/settings/basic_page/basic_page.js +++ b/chrome/browser/resources/settings/basic_page/basic_page.js
@@ -29,6 +29,7 @@ advancedToggleExpanded: { type: Boolean, notify: true, + observer: 'advancedToggleExpandedChanged_', }, /** @@ -101,7 +102,7 @@ if (this.pageVisibility.advancedSettings !== false) { assert(whenSearchDone === settings.getSearchManager().search( - query, assert(this.$$('#advancedPage')))); + query, assert(this.$.advancedPageTemplate.get()))); } return whenSearchDone; @@ -131,6 +132,15 @@ }, /** + * Render the advanced page now (don't wait for idle). + * @private + */ + advancedToggleExpandedChanged_: function() { + if (this.advancedToggleExpanded) + this.$.advancedPageTemplate.get(); + }, + + /** * @param {boolean} inSearchMode * @param {boolean} hasExpandedSection * @return {boolean}
diff --git a/chrome/browser/resources/settings/controls/settings_idle_render.html b/chrome/browser/resources/settings/controls/settings_idle_render.html new file mode 100644 index 0000000..dda6b0a --- /dev/null +++ b/chrome/browser/resources/settings/controls/settings_idle_render.html
@@ -0,0 +1,3 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> + +<script src="settings_idle_render.js"></script>
diff --git a/chrome/browser/resources/settings/controls/settings_idle_render.js b/chrome/browser/resources/settings/controls/settings_idle_render.js new file mode 100644 index 0000000..8e224c9 --- /dev/null +++ b/chrome/browser/resources/settings/controls/settings_idle_render.js
@@ -0,0 +1,76 @@ +// 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. + +/** + * @fileoverview + * settings-idle-render is a simple variant of dom-if designed for lazy + * rendering of elements that are accessed imperatively. + * If a use for idle time expansion is found outside of settings, this code + * should be replaced by cr-lazy-render after that feature is merged into + * ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.js + */ + +Polymer({ + is: 'settings-idle-render', + extends: 'template', + + behaviors: [Polymer.Templatizer], + + /** @private {TemplatizerNode} */ + child_: null, + + /** @private {number} */ + idleCallback_: 0, + + /** @override */ + attached: function() { + this.idleCallback_ = requestIdleCallback(this.render_.bind(this)); + }, + + /** @override */ + detached: function() { + // No-op if callback already fired. + cancelIdleCallback(this.idleCallback_); + }, + + /** + * Stamp the template into the DOM tree synchronously + * @return {Element} Child element which has been stamped into the DOM tree. + */ + get: function() { + if (!this.child_) + this.render_(); + return this.child_; + }, + + /** @private */ + render_: function() { + if (!this.ctor) + this.templatize(this); + var parentNode = this.parentNode; + if (parentNode && !this.child_) { + var instance = this.stamp({}); + this.child_ = instance.root.firstElementChild; + parentNode.insertBefore(instance.root, this); + } + }, + + /** + * @param {string} prop + * @param {Object} value + */ + _forwardParentProp: function(prop, value) { + if (this.child_) + this.child_._templateInstance[prop] = value; + }, + + /** + * @param {string} path + * @param {Object} value + */ + _forwardParentPath: function(path, value) { + if (this.child_) + this.child_._templateInstance.notifyPath(path, value, true); + } +});
diff --git a/chrome/browser/resources/settings/device_page/device_page.html b/chrome/browser/resources/settings/device_page/device_page.html index e50598a..c0a6aa5 100644 --- a/chrome/browser/resources/settings/device_page/device_page.html +++ b/chrome/browser/resources/settings/device_page/device_page.html
@@ -38,7 +38,7 @@ <div class="middle">$i18n{keyboardTitle}</div> <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> - <template is="dom-if" if="[[stylusAllowed_]]"> + <template is="dom-if" if="[[hasStylus_]]"> <div id="stylusRow" class="settings-box" on-tap="onStylusTap_" actionable> <iron-icon icon="settings:note"></iron-icon> @@ -104,14 +104,12 @@ <settings-keyboard prefs="{{prefs}}"></settings-keyboard> </settings-subpage> </template> - <template is="dom-if" if="[[stylusAllowed_]]"> - <template is="dom-if" route-path="/stylus"> - <settings-subpage - associated-control="[[$$('#stylusRow')]]" - page-title="$i18n{stylusTitle}"> - <settings-stylus prefs="{{prefs}}"></settings-stylus> - </settings-subpage> - </template> + <template is="dom-if" route-path="/stylus"> + <settings-subpage + associated-control="[[$$('#stylusRow')]]" + page-title="$i18n{stylusTitle}"> + <settings-stylus prefs="{{prefs}}"></settings-stylus> + </settings-subpage> </template> <template is="dom-if" route-path="/display"> <settings-subpage
diff --git a/chrome/browser/resources/settings/device_page/device_page.js b/chrome/browser/resources/settings/device_page/device_page.js index b3bb4acc..23a004e 100644 --- a/chrome/browser/resources/settings/device_page/device_page.js +++ b/chrome/browser/resources/settings/device_page/device_page.js
@@ -22,22 +22,25 @@ }, /** - * |hasMouse_| and |hasTouchpad_| start undefined so observers don't trigger - * until both have been populated. + * |hasMouse_|, |hasTouchpad_|, and |hasStylus_| start undefined so + * observers don't trigger until they have been populated. * @private */ - hasMouse_: Boolean, - - /** @private */ - hasTouchpad_: Boolean, - - /** @private */ - stylusAllowed_: { + hasMouse_: { type: Boolean, - value: function() { - return loadTimeData.getBoolean('stylusAllowed'); - }, - readOnly: true, + value: false + }, + + /** @private */ + hasTouchpad_: { + type: Boolean, + value: false + }, + + /** @private */ + hasStylus_: { + type: Boolean, + value: false }, /** @@ -109,6 +112,10 @@ 'has-touchpad-changed', this.set.bind(this, 'hasTouchpad_')); settings.DevicePageBrowserProxyImpl.getInstance().initializePointers(); + this.addWebUIListener( + 'has-stylus-changed', this.set.bind(this, 'hasStylus_')); + settings.DevicePageBrowserProxyImpl.getInstance().initializeStylus(); + if (this.enablePowerSettings_) { this.addWebUIListener( 'battery-status-changed', this.set.bind(this, 'batteryStatus_'));
diff --git a/chrome/browser/resources/settings/device_page/device_page_browser_proxy.js b/chrome/browser/resources/settings/device_page/device_page_browser_proxy.js index cd7cf7d..e9d2737 100644 --- a/chrome/browser/resources/settings/device_page/device_page_browser_proxy.js +++ b/chrome/browser/resources/settings/device_page/device_page_browser_proxy.js
@@ -46,6 +46,9 @@ /** Initializes the mouse and touchpad handler. */ initializePointers: function() {}, + /** Initializes the stylus handler. */ + initializeStylus: function() {}, + /** * Override to interact with the on-tap/on-keydown event on the Learn More * link. @@ -103,6 +106,11 @@ chrome.send('initializePointerSettings'); }, + /** @override */ + initializeStylus: function() { + chrome.send('initializeStylusSettings'); + }, + /** override */ handleLinkEvent: function(e) { // Prevent the link from activating its parent element when tapped or
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html index 6f52390..c6c14a1e 100644 --- a/chrome/browser/resources/settings/privacy_page/privacy_page.html +++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -438,16 +438,19 @@ </site-data-details-subpage> </settings-subpage> </template> -<if expr="chromeos or is_win"> <template is="dom-if" route-path="/content/protectedContent" no-search> <settings-subpage page-title="$i18n{siteSettingsProtectedContent}"> <div class="settings-box first two-line"> $i18n{siteSettingsProtectedContentExplanation} </div> <div class="settings-box first"> + <!-- TODO(dschuyler): change i18n to i18nStr. --> <settings-toggle-button class="start" pref="{{prefs.settings.privacy.drm_enabled}}" - label="$i18n{siteSettingsProtectedContentEnable}"> + label="[[getStringTernary_( + prefs.settings.privacy.drm_enabled.value, + '$i18n{siteSettingsProtectedContentEnable}', + '$i18n{siteSettingsBlocked}')]]"> </settings-toggle-button> </div> <if expr="chromeos"> @@ -457,7 +460,6 @@ </if> </settings-subpage> </template> -</if> </settings-animated-pages> </template> <script src="privacy_page.js"></script>
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.js b/chrome/browser/resources/settings/privacy_page/privacy_page.js index faf61cd..8e0c4b0 100644 --- a/chrome/browser/resources/settings/privacy_page/privacy_page.js +++ b/chrome/browser/resources/settings/privacy_page/privacy_page.js
@@ -173,4 +173,15 @@ 'documentation/en/flashplayer/help/settings_manager07.html'); }, // </if> + + /** + * Works like a ternary operator. E.g. (value ? trueLabel: falseLabel). + * @param {boolean} value + * @param {string} trueLabel True label (for example, 'Allow DRM'). + * @param {string} falseLabel False label (for example, 'Blocked'). + * @private + */ + getStringTernary_: function(value, trueLabel, falseLabel) { + return value ? trueLabel : falseLabel; + }, });
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js index 14a485e..7457f60 100644 --- a/chrome/browser/resources/settings/route.js +++ b/chrome/browser/resources/settings/route.js
@@ -173,11 +173,8 @@ r.SITE_SETTINGS_USB_DEVICES = r.SITE_SETTINGS.createChild('usbDevices'); r.SITE_SETTINGS_ZOOM_LEVELS = r.SITE_SETTINGS.createChild('zoomLevels'); r.SITE_SETTINGS_PDF_DOCUMENTS = r.SITE_SETTINGS.createChild('pdfDocuments'); - -// <if expr="chromeos or is_win"> r.SITE_SETTINGS_PROTECTED_CONTENT = r.SITE_SETTINGS.createChild('protectedContent'); -// </if> // <if expr="chromeos"> r.DATETIME = r.ADVANCED.createSection('/dateTime', 'dateTime');
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd index bd24b85..ed42920 100644 --- a/chrome/browser/resources/settings/settings_resources.grd +++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -405,6 +405,12 @@ <structure name="IDR_SETTINGS_CONTROLS_RADIO_GROUP_JS" file="controls/settings_radio_group.js" type="chrome_html" /> + <structure name="IDR_SETTINGS_CONTROLS_SETTINGS_IDLE_RENDER_HTML" + file="controls/settings_idle_render.html" + type="chrome_html" /> + <structure name="IDR_SETTINGS_CONTROLS_SETTINGS_IDLE_RENDER_JS" + file="controls/settings_idle_render.js" + type="chrome_html" /> <structure name="IDR_SETTINGS_CONTROLS_TOGGLE_BUTTON_HTML" file="controls/settings_toggle_button.html" type="chrome_html" /> @@ -850,8 +856,7 @@ type="chrome_html" /> <structure name="IDR_SETTINGS_SITE_SETTINGS_PAGE_HTML" file="site_settings_page/site_settings_page.html" - type="chrome_html" - preprocess="true" /> + type="chrome_html" /> <structure name="IDR_SETTINGS_SITE_SETTINGS_PAGE_JS" file="site_settings_page/site_settings_page.js" type="chrome_html" />
diff --git a/chrome/browser/resources/settings/settings_vars_css.html b/chrome/browser/resources/settings/settings_vars_css.html index 3a1b909..1adde52 100644 --- a/chrome/browser/resources/settings/settings_vars_css.html +++ b/chrome/browser/resources/settings/settings_vars_css.html
@@ -32,14 +32,16 @@ --settings-page-vertical-margin: 21px; + /* TODO (scottchen): re-implement with paddings instead; */ /* These are used for row items such as radio buttons, check boxes, list * items etc. */ - --settings-row-min-height: 44px; - --settings-row-two-line-min-height: 56px; + --settings-row-min-height: 45px; + --settings-row-two-line-min-height: 64px; + /* TODO (scottchen): re-implement with paddings instead; */ /* These are used for the settings-box containers, which may contain one or * more "row items". */ - --settings-box-min-height: 48px; + --settings-box-min-height: 45px; --settings-box-two-line-min-height: 64px; --settings-box-three-line-min-height: 84px; @@ -85,9 +87,15 @@ --iron-icon-width: var(--cr-icon-size); --paper-checkbox-label-color: inherit; --paper-dialog-color: inherit; + + --cr-icon-ripple-size: 40px; --paper-icon-button: { - height: var(--cr-icon-ripple-size); - width: var(--cr-icon-ripple-size); + /** + * This makes the icons 20px (in combination with "--cr-icon-ripple-size: + * 40px"), since paper-icon-button>iron-icon width and height are + * hardcoded to 100%. + */ + padding: 10px; }; --paper-input-container-focus-color: var(--google-blue-500); --paper-input-container-input: {
diff --git a/chrome/browser/resources/settings/site_settings/zoom_levels.html b/chrome/browser/resources/settings/site_settings/zoom_levels.html index 3d385cb..2806ac8 100644 --- a/chrome/browser/resources/settings/site_settings/zoom_levels.html +++ b/chrome/browser/resources/settings/site_settings/zoom_levels.html
@@ -14,6 +14,10 @@ display: block; } + .zoom-label { + -webkit-margin-end: 16px; + } + .empty-message { margin-top: 15px; } @@ -28,7 +32,7 @@ <div class="middle"> <div>[[item.displayName]]</div> </div> - <div>[[item.zoom]]</div> + <div class="zoom-label">[[item.zoom]]</div> <div> <paper-icon-button icon="cr:clear" on-tap="removeZoomLevel_">
diff --git a/chrome/browser/resources/settings/site_settings_page/site_settings_page.html b/chrome/browser/resources/settings/site_settings_page/site_settings_page.html index 2bad2a6..5cd0d26 100644 --- a/chrome/browser/resources/settings/site_settings_page/site_settings_page.html +++ b/chrome/browser/resources/settings/site_settings_page/site_settings_page.html
@@ -10,7 +10,11 @@ <dom-module id="settings-site-settings-page"> <template> - <style include="settings-shared"></style> + <style include="settings-shared"> + .settings-box iron-icon + .middle { + -webkit-padding-start: 20px; + } + </style> <template is="dom-if" if="[[enableSiteSettings_]]"> <div class="settings-box first" category$="[[ALL_SITES]]" data-route="SITE_SETTINGS_ALL" on-tap="onTapNavigate_" actionable> @@ -245,14 +249,12 @@ <div class="middle">$i18n{siteSettingsPdfDocuments}</div> <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> -<if expr="chromeos or is_win"> <div class="settings-box" data-route="SITE_SETTINGS_PROTECTED_CONTENT" on-tap="onTapNavigate_" actionable> <iron-icon icon="settings:security"></iron-icon> <div class="middle">$i18n{siteSettingsProtectedContent}</div> <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> -</if> </template> <script src="site_settings_page.js"></script> </dom-module>
diff --git a/chrome/browser/resources/ssl/ssl_error_assistant/ssl_error_assistant.asciipb b/chrome/browser/resources/ssl/ssl_error_assistant/ssl_error_assistant.asciipb index a6714bf5..64755fd 100644 --- a/chrome/browser/resources/ssl/ssl_error_assistant/ssl_error_assistant.asciipb +++ b/chrome/browser/resources/ssl/ssl_error_assistant/ssl_error_assistant.asciipb
@@ -2,17 +2,14 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -# Placeholder for list of known certificates that are treated as captive -# portal certificates. +# Placeholder list for SPKI hashes of certificates that are treated as captive +# portal certificates. See chrome/browser/ssl/ssl_error_assistant.proto for the +# full format. # TODO(crbug.com/640835): Populate this with full list. version_id: 1 -# See chrome/browser/ssl/tls_error_assistant.proto for the full format. +# https://captive-portal.badssl.com leaf: captive_portal_cert { - - # Sha256 hash of the certificate's public key. The fingerprint is prefixed - # with "sha256/" and encoded in base64 (same format as - # src/net/http/transport_security_state_static.pins) - sha256_hash: "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + sha256_hash: "sha256/fjZPHewEHTrMDX3I1ecEIeoy3WFxHyGplOLv28kIbtI=" }
diff --git a/chrome/browser/resources/vulcanize.gni b/chrome/browser/resources/vulcanize.gni index d782bc3..87d708a 100644 --- a/chrome/browser/resources/vulcanize.gni +++ b/chrome/browser/resources/vulcanize.gni
@@ -43,8 +43,6 @@ invoker.html_out_file, "--js_out_file", invoker.js_out_file, - "--input_type", - invoker.input_type, "--input", invoker.input, "--insert_in_head",
diff --git a/chrome/browser/resources/vulcanize_gn.py b/chrome/browser/resources/vulcanize_gn.py index 91893308..d492678 100755 --- a/chrome/browser/resources/vulcanize_gn.py +++ b/chrome/browser/resources/vulcanize_gn.py
@@ -15,7 +15,7 @@ _HERE_PATH = os.path.dirname(__file__) _SRC_PATH = os.path.normpath(os.path.join(_HERE_PATH, '..', '..', '..')) -_CWD = os.getcwd() +_CWD = os.getcwd() # NOTE(dbeam): this is typically out/<gn_name>/. sys.path.append(os.path.join(_SRC_PATH, 'third_party', 'node')) import node @@ -96,6 +96,7 @@ for (redirect_url, file_path) in mappings: if url.startswith(redirect_url): return url.replace(redirect_url, file_path + os.sep) + # TODO(dbeam): can we make this stricter? return url @@ -106,8 +107,22 @@ out_path = os.path.join(_CWD, args.out_folder) # Prior call to vulcanize already generated the deps list, grab it from there. - request_list = open(os.path.join( - out_path, _REQUEST_LIST_FILE), 'r').read().splitlines() + request_list_path = os.path.join(out_path, _REQUEST_LIST_FILE) + request_list = open(request_list_path, 'r').read().splitlines() + + if platform.system() == 'Windows': + # TODO(dbeam): UGH. For some reason Vulcanize is interpreting the target + # file path as a URL and using the drive letter (e.g. D:\) as a protocol. + # This is a little insane, but we're fixing here by normalizing case (which + # really shouldn't matter, these are all file paths and generally are all + # lower case) and writing from / to \ (file path) and then back again. This + # is compounded by NodeJS having a bug in url.resolve() that handles + # chrome:// protocol URLs poorly as well as us using startswith() to strip + # file paths (which isn't crazy awesome either). Don't remove unless you + # really really know what you're doing. + norm = lambda u: u.lower().replace('/', '\\') + request_list = [norm(u).replace(norm(in_path), '').replace('\\', '/') + for u in request_list] # Undo the URL mappings applied by vulcanize to get file paths relative to # current working directory. @@ -116,21 +131,18 @@ ('chrome://%s/' % args.host, os.path.relpath(in_path, _CWD)), ] - dependencies = map( - lambda url: _undo_mapping(url_mappings, url), request_list) + deps = [_undo_mapping(url_mappings, u) for u in request_list] + deps = map(os.path.normpath, deps) # If the input was a .pak file, the generated depfile should not list files # already in the .pak file. - filtered_dependencies = dependencies - if (args.input_type == 'PAK_FILE'): + if args.input.endswith('.pak'): filter_url = os.path.join(args.out_folder, _PAK_UNPACK_FOLDER) - filtered_dependencies = filter( - lambda url: not url.startswith(filter_url), dependencies) + deps = [d for d in deps if not d.startswith(filter_url)] with open(os.path.join(_CWD, args.depfile), 'w') as f: - f.write(os.path.join( - args.out_folder, args.html_out_file) + ': ' + ' '.join( - filtered_dependencies)) + deps_file_header = os.path.join(args.out_folder, args.html_out_file) + f.write(deps_file_header + ': ' + ' '.join(deps)) def _vulcanize(in_folder, args): @@ -157,6 +169,8 @@ if args.insert_in_head: assert '<head>' in output + # NOTE(dbeam): Vulcanize eats <base> tags after processing. This undoes + # that by adding a <base> tag to the (post-processed) generated output. output = output.replace('<head>', '<head>' + args.insert_in_head) with tempfile.NamedTemporaryFile(mode='wt+', delete=False) as tmp: @@ -180,30 +194,35 @@ def _css_build(out_folder, files): out_path = os.path.join(_CWD, out_folder) - paths = map(lambda f: os.path.join(out_path, f), files) + paths = [os.path.join(out_path, f) for f in files] _run_node([node_modules.PathToPolymerCssBuild()] + paths) -def main(): +def main(argv): parser = argparse.ArgumentParser() - parser.add_argument('--depfile') - parser.add_argument('--host') - parser.add_argument('--html_in_file') - parser.add_argument('--html_out_file') - parser.add_argument('--input') - parser.add_argument('--input_type') + parser.add_argument('--depfile', required=True) + parser.add_argument('--host', required=True) + parser.add_argument('--html_in_file', required=True) + parser.add_argument('--html_out_file', required=True) + parser.add_argument('--input', required=True) parser.add_argument('--insert_in_head') - parser.add_argument('--js_out_file') - parser.add_argument('--out_folder') - args = parser.parse_args() + parser.add_argument('--js_out_file', required=True) + parser.add_argument('--out_folder', required=True) + args = parser.parse_args(argv) + + # NOTE(dbeam): on Windows, GN can send dirs/like/this. When joined, you might + # get dirs/like/this\file.txt. This looks odd to windows. Normalize to right + # the slashes. + args.depfile = os.path.normpath(args.depfile) args.input = os.path.normpath(args.input) + args.out_folder = os.path.normpath(args.out_folder) vulcanize_input_folder = args.input # If a .pak file was specified, unpack that file first and pass the output to # vulcanize. - if (args.input_type == 'PAK_FILE'): + if args.input.endswith('.pak'): import unpack_pak input_folder = os.path.join(_CWD, args.input) output_folder = os.path.join(args.out_folder, _PAK_UNPACK_FOLDER) @@ -217,4 +236,4 @@ if __name__ == '__main__': - main() + main(sys.argv[1:])
diff --git a/chrome/browser/resources/vulcanize_gn_test.py b/chrome/browser/resources/vulcanize_gn_test.py new file mode 100755 index 0000000..702f5a4 --- /dev/null +++ b/chrome/browser/resources/vulcanize_gn_test.py
@@ -0,0 +1,84 @@ +#!/usr/bin/env python +# 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. + +import os +import shutil +import tempfile +import unittest +import vulcanize_gn + + +_HERE_DIR = os.path.dirname(__file__) + + +class VulcanizeGnTest(unittest.TestCase): + def setUp(self): + self._out_folder = None + self._tmp_dirs = [] + self._tmp_src_dir = None + + def tearDown(self): + for tmp_dir in self._tmp_dirs: + shutil.rmtree(tmp_dir) + + def _write_file_to_src_dir(self, file_name, file_contents): + if not self._tmp_src_dir: + self._tmp_src_dir = self._create_tmp_dir() + with open(os.path.join(self._tmp_src_dir, file_name), 'w') as tmp_file: + tmp_file.write(file_contents) + + def _create_tmp_dir(self): + # TODO(dbeam): support cross-drive paths (i.e. d:\ vs c:\). + tmp_dir = tempfile.mkdtemp(dir=_HERE_DIR) + self._tmp_dirs.append(tmp_dir) + return tmp_dir + + def _read_out_file(self, file_name): + assert self._out_folder + return open(os.path.join(self._out_folder, file_name), 'r').read() + + def _run_vulcanize(self, depfile, html_in_file, html_out_file, js_out_file): + # TODO(dbeam): make it possible to _run_vulcanize twice? Is that useful? + assert not self._out_folder + self._out_folder = self._create_tmp_dir() + vulcanize_gn.main([ + '--depfile', os.path.join(self._out_folder,'depfile.d'), + '--html_in_file', html_in_file, + '--html_out_file', html_out_file, + '--host', 'fake-host', + '--input', self._tmp_src_dir, + '--js_out_file', js_out_file, + '--out_folder', self._out_folder, + ]) + + + def testSimpleVulcanize(self): + self._write_file_to_src_dir('element.html', '<div>got here!</div>') + self._write_file_to_src_dir('element.js', "alert('yay');") + self._write_file_to_src_dir('ui.html', ''' +<link rel="import" href="element.html"> +<script src="element.js"></script> +''') + + self._run_vulcanize(depfile='depfile.d', + html_in_file='ui.html', + html_out_file='fast.html', + js_out_file='fast.js') + + fast_html = self._read_out_file('fast.html') + self.assertFalse('element.html' in fast_html) + self.assertFalse('element.js' in fast_html) + self.assertTrue('got here!' in fast_html) + + fast_js = self._read_out_file('fast.js') + self.assertTrue('yay' in fast_js) + + depfile_d = self._read_out_file('depfile.d') + self.assertTrue('element.html' in depfile_d) + self.assertTrue('element.js' in depfile_d) + + +if __name__ == '__main__': + unittest.main()
diff --git a/chrome/browser/resources/webapks/about_webapks.css b/chrome/browser/resources/webapks/about_webapks.css new file mode 100644 index 0000000..11ceac58 --- /dev/null +++ b/chrome/browser/resources/webapks/about_webapks.css
@@ -0,0 +1,48 @@ +/* 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. */ + +body { + background-color: white; + color: black; + font-size: 100%; + margin: 0; +} + +#outer { + margin-left: auto; + margin-right: auto; + margin-top: 10px; + width: 90%; +} + +.label { + -webkit-padding-end: 5px; + font-size: 1.5em; + font-weight: bold; + text-align: start; + white-space: nowrap; +} + +#logo { + display: block; + margin-bottom: 10px; + margin-left: auto; + margin-right: auto; +} + +.app-name { + -webkit-padding-end: 5px; + display: block; + font-size: 1.2em; + font-weight: bold; + margin-top: 20px; + white-space: nowrap; +} + +.app-property-label { + -webkit-padding-end: 5px; + font-weight: bold; + text-align: start; + white-space: nowrap; +}
diff --git a/chrome/browser/resources/webapks/about_webapks.html b/chrome/browser/resources/webapks/about_webapks.html new file mode 100644 index 0000000..fb87afd --- /dev/null +++ b/chrome/browser/resources/webapks/about_webapks.html
@@ -0,0 +1,32 @@ +<!doctype html> + +<!-- +about:webapks template page +--> + +<html lang="en" dir="ltr"> + <head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width"> + <title>About WebAPKs</title> + <link rel="stylesheet" href="chrome://resources/css/text_defaults.css"> + <link rel="stylesheet" href="about_webapks.css"> + + <script src="chrome://resources/js/cr.js"></script> + <script src="chrome://resources/js/load_time_data.js"></script> + <script src="chrome://resources/js/parse_html_subset.js"></script> + <script src="chrome://resources/js/util.js"></script> + <script src="chrome://webapks/webapks.js"></script> + <script src="chrome://webapks/strings.js"></script> + </head> + + <body> + <div id="outer"> + <div> + <span class="label">WebAPKs:</span> + </div> + + <div class="content" id="webapk-list"></div> + </div> + </body> +</html>
diff --git a/chrome/browser/resources/webapks/about_webapks.js b/chrome/browser/resources/webapks/about_webapks.js new file mode 100644 index 0000000..ae929d6 --- /dev/null +++ b/chrome/browser/resources/webapks/about_webapks.js
@@ -0,0 +1,71 @@ +// 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. + +/** + * @typedef {{ + * shortName: string, + * packageName: string, + * shellApkVersion: number, + * versionCode: number + * }} + */ +var WebApkInfo; + +/** + * Creates and returns an element (with |text| as content) assigning it the + * |className| class. + * + * @param {string} text Text to be shown in the span. + * @param {string} className Class to be assigned to the new element. + * @return {Element} The created element. + */ +function createSpanWithTextAndClass(text, className) { + var element = createElementWithClassName('span', className); + element.textContent = text; + return element; +} + +/** + * Callback from the backend with the information of a WebAPK to display. + * This will be called once for each WebAPK available on the device and each + * one will be appended at the end of the other. + * + * @param {!Array<WebApkInfo>} webApkList List of objects with information about + * WebAPKs installed. + */ +function returnWebApksInfo(webApkList) { + for (let webApkInfo of webApkList) { + addWebApk(webApkInfo); + } +} + +/** + * Adds a new entry to the page with the information of a WebAPK. + * + * @param {WebApkInfo} webApkInfo Information about an installed WebAPK. + */ +function addWebApk(webApkInfo) { + var webApkList = $('webapk-list'); + + webApkList.appendChild( + createSpanWithTextAndClass(webApkInfo.shortName, 'app-name')); + + webApkList.appendChild( + createSpanWithTextAndClass('Package name: ', 'app-property-label')); + webApkList.appendChild(document.createTextNode(webApkInfo.packageName)); + + webApkList.appendChild(document.createElement('br')); + webApkList.appendChild(createSpanWithTextAndClass( + 'Shell APK version: ', 'app-property-label')); + webApkList.appendChild(document.createTextNode(webApkInfo.shellApkVersion)); + + webApkList.appendChild(document.createElement('br')); + webApkList.appendChild( + createSpanWithTextAndClass('Version code: ', 'app-property-label')); + webApkList.appendChild(document.createTextNode(webApkInfo.versionCode)); +} + +document.addEventListener('DOMContentLoaded', function() { + chrome.send('requestWebApksInfo'); +});
diff --git a/chrome/browser/resources/webapks/compiled_resources2.gyp b/chrome/browser/resources/webapks/compiled_resources2.gyp new file mode 100644 index 0000000..dcb778b --- /dev/null +++ b/chrome/browser/resources/webapks/compiled_resources2.gyp
@@ -0,0 +1,15 @@ +# 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. +{ + 'targets': [ + { + 'target_name': 'about_webapks', + 'dependencies': [ + '<(EXTERNS_GYP):chrome_send', + '../../../../ui/webui/resources/js/compiled_resources2.gyp:util', + ], + 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + ], +}
diff --git a/chrome/browser/resources/webapks_ui_resources.grd b/chrome/browser/resources/webapks_ui_resources.grd new file mode 100644 index 0000000..063053a --- /dev/null +++ b/chrome/browser/resources/webapks_ui_resources.grd
@@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<grit latest_public_release="0" current_release="1" output_all_resource_defines="false"> + <outputs> + <output filename="grit/webapks_ui_resources.h" type="rc_header"> + <emit emit_type='prepend'></emit> + </output> + <output filename="webapks_ui_resources.pak" type="data_package" /> + </outputs> + <release seq="1"> + <includes> + <include name="IDR_WEBAPKS_UI_CSS" file="webapks/about_webapks.css" type="BINDATA" compress="gzip" /> + <include name="IDR_WEBAPKS_UI_HTML" file="webapks/about_webapks.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" /> + <include name="IDR_WEBAPKS_UI_JS" file="webapks/about_webapks.js" type="BINDATA" compress="gzip" /> + </includes> + </release> +</grit>
diff --git a/chrome/browser/safe_browsing/client_side_detection_host.cc b/chrome/browser/safe_browsing/client_side_detection_host.cc index 7df4ce7ef..132b230 100644 --- a/chrome/browser/safe_browsing/client_side_detection_host.cc +++ b/chrome/browser/safe_browsing/client_side_detection_host.cc
@@ -27,14 +27,15 @@ #include "components/safe_browsing_db/safe_browsing_prefs.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/navigation_controller.h" -#include "content/public/browser/navigation_details.h" #include "content/public/browser/navigation_entry.h" +#include "content/public/browser/navigation_handle.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/resource_request_details.h" #include "content/public/browser/web_contents.h" #include "content/public/common/frame_navigate_params.h" #include "content/public/common/url_constants.h" +#include "net/http/http_response_headers.h" #include "url/gurl.h" using content::BrowserThread; @@ -62,15 +63,14 @@ ClientSideDetectionHost::ShouldClassifyUrlRequest> { public: ShouldClassifyUrlRequest( - const content::FrameNavigateParams& params, + content::NavigationHandle* navigation_handle, const ShouldClassifyUrlCallback& start_phishing_classification, const ShouldClassifyUrlCallback& start_malware_classification, WebContents* web_contents, ClientSideDetectionService* csd_service, SafeBrowsingDatabaseManager* database_manager, ClientSideDetectionHost* host) - : params_(params), - web_contents_(web_contents), + : web_contents_(web_contents), csd_service_(csd_service), database_manager_(database_manager), host_(host), @@ -81,6 +81,10 @@ DCHECK(csd_service_); DCHECK(database_manager_.get()); DCHECK(host_); + url_ = navigation_handle->GetURL(); + if (navigation_handle->GetResponseHeaders()) + navigation_handle->GetResponseHeaders()->GetMimeType(&mime_type_); + socket_address_ = navigation_handle->GetSocketAddress(); } void Start() { @@ -91,34 +95,33 @@ UMA_HISTOGRAM_BOOLEAN("SBClientMalware.ClassificationStart", 1); // Only classify [X]HTML documents. - if (params_.contents_mime_type != "text/html" && - params_.contents_mime_type != "application/xhtml+xml") { - DVLOG(1) << "Skipping phishing classification for URL: " << params_.url + if (mime_type_ != "text/html" && mime_type_ != "application/xhtml+xml") { + DVLOG(1) << "Skipping phishing classification for URL: " << url_ << " because it has an unsupported MIME type: " - << params_.contents_mime_type; + << mime_type_; DontClassifyForPhishing(NO_CLASSIFY_UNSUPPORTED_MIME_TYPE); } - if (csd_service_->IsPrivateIPAddress(params_.socket_address.host())) { - DVLOG(1) << "Skipping phishing classification for URL: " << params_.url + if (csd_service_->IsPrivateIPAddress(socket_address_.host())) { + DVLOG(1) << "Skipping phishing classification for URL: " << url_ << " because of hosting on private IP: " - << params_.socket_address.host(); + << socket_address_.host(); DontClassifyForPhishing(NO_CLASSIFY_PRIVATE_IP); DontClassifyForMalware(NO_CLASSIFY_PRIVATE_IP); } // For phishing we only classify HTTP pages. - if (!params_.url.SchemeIs(url::kHttpScheme)) { - DVLOG(1) << "Skipping phishing classification for URL: " << params_.url + if (!url_.SchemeIs(url::kHttpScheme)) { + DVLOG(1) << "Skipping phishing classification for URL: " << url_ << " because it is not HTTP: " - << params_.socket_address.host(); + << socket_address_.host(); DontClassifyForPhishing(NO_CLASSIFY_NOT_HTTP_URL); } // Don't run any classifier if the tab is incognito. if (web_contents_->GetBrowserContext()->IsOffTheRecord()) { DVLOG(1) << "Skipping phishing and malware classification for URL: " - << params_.url << " because we're browsing incognito."; + << url_ << " because we're browsing incognito."; DontClassifyForPhishing(NO_CLASSIFY_OFF_THE_RECORD); DontClassifyForMalware(NO_CLASSIFY_OFF_THE_RECORD); } @@ -133,7 +136,7 @@ BrowserThread::IO, FROM_HERE, base::Bind(&ShouldClassifyUrlRequest::CheckSafeBrowsingDatabase, - this, params_.url)); + this, url_)); } } @@ -251,11 +254,11 @@ // If result is cached, we don't want to run classification again. // In that case we're just trying to show the warning. bool is_phishing; - if (csd_service_->GetValidCachedResult(params_.url, &is_phishing)) { - DVLOG(1) << "Satisfying request for " << params_.url << " from cache"; + if (csd_service_->GetValidCachedResult(url_, &is_phishing)) { + DVLOG(1) << "Satisfying request for " << url_ << " from cache"; UMA_HISTOGRAM_BOOLEAN("SBClientPhishing.RequestSatisfiedFromCache", 1); // Since we are already on the UI thread, this is safe. - host_->MaybeShowPhishingWarning(params_.url, is_phishing); + host_->MaybeShowPhishingWarning(url_, is_phishing); DontClassifyForPhishing(NO_CLASSIFY_RESULT_FROM_CACHE); } @@ -264,13 +267,13 @@ // too many pages as phishing, but for those that we already think are // phishing we want to send a request to the server to give ourselves // a chance to fix misclassifications. - if (csd_service_->IsInCache(params_.url)) { - DVLOG(1) << "Reporting limit skipped for " << params_.url + if (csd_service_->IsInCache(url_)) { + DVLOG(1) << "Reporting limit skipped for " << url_ << " as it was in the cache."; UMA_HISTOGRAM_BOOLEAN("SBClientPhishing.ReportLimitSkipped", 1); } else if (csd_service_->OverPhishingReportLimit()) { DVLOG(1) << "Too many report phishing requests sent recently, " - << "not running classification for " << params_.url; + << "not running classification for " << url_; DontClassifyForPhishing(NO_CLASSIFY_TOO_MANY_REPORTS); } if (csd_service_->OverMalwareReportLimit()) { @@ -294,7 +297,9 @@ } } - content::FrameNavigateParams params_; + GURL url_; + std::string mime_type_; + net::HostPortPair socket_address_; WebContents* web_contents_; ClientSideDetectionService* csd_service_; // We keep a ref pointer here just to make sure the safe browsing @@ -354,13 +359,15 @@ return handled; } -void ClientSideDetectionHost::DidNavigateMainFrame( - const content::LoadCommittedDetails& details, - const content::FrameNavigateParams& params) { +void ClientSideDetectionHost::DidFinishNavigation( + content::NavigationHandle* navigation_handle) { + if (!navigation_handle->IsInMainFrame() || !navigation_handle->HasCommitted()) + return; + // TODO(noelutz): move this DCHECK to WebContents and fix all the unit tests // that don't call this method on the UI thread. // DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (details.is_in_page) { + if (navigation_handle->IsSamePage()) { // If the navigation is within the same page, the user isn't really // navigating away. We don't need to cancel a pending callback or // begin a new classification. @@ -383,15 +390,18 @@ browse_info_.reset(new BrowseInfo); // Store redirect chain information. - if (params.url.host() != cur_host_) { - cur_host_ = params.url.host(); - cur_host_redirects_ = params.redirects; + if (navigation_handle->GetURL().host() != cur_host_) { + cur_host_ = navigation_handle->GetURL().host(); + cur_host_redirects_ = navigation_handle->GetRedirectChain(); } - browse_info_->url = params.url; + browse_info_->url = navigation_handle->GetURL(); browse_info_->host_redirects = cur_host_redirects_; - browse_info_->url_redirects = params.redirects; - browse_info_->referrer = params.referrer.url; - browse_info_->http_status_code = details.http_status_code; + browse_info_->url_redirects = navigation_handle->GetRedirectChain(); + browse_info_->referrer = navigation_handle->GetReferrer().url; + if (navigation_handle->GetResponseHeaders()) { + browse_info_->http_status_code = + navigation_handle->GetResponseHeaders()->response_code(); + } should_extract_malware_features_ = true; should_classify_for_malware_ = false; @@ -399,7 +409,7 @@ // Check whether we can cassify the current URL for phishing or malware. classification_request_ = new ShouldClassifyUrlRequest( - params, + navigation_handle, base::Bind(&ClientSideDetectionHost::OnPhishingPreClassificationDone, weak_factory_.GetWeakPtr()), base::Bind(&ClientSideDetectionHost::OnMalwarePreClassificationDone,
diff --git a/chrome/browser/safe_browsing/client_side_detection_host.h b/chrome/browser/safe_browsing/client_side_detection_host.h index f107302..1b82f1b 100644 --- a/chrome/browser/safe_browsing/client_side_detection_host.h +++ b/chrome/browser/safe_browsing/client_side_detection_host.h
@@ -46,9 +46,8 @@ // From content::WebContentsObserver. If we navigate away we cancel all // pending callbacks that could show an interstitial, and check to see whether // we should classify the new URL. - void DidNavigateMainFrame( - const content::LoadCommittedDetails& details, - const content::FrameNavigateParams& params) override; + void DidFinishNavigation( + content::NavigationHandle* navigation_handle) override; // Called when the SafeBrowsingService found a hit with one of the // SafeBrowsing lists. This method is called on the UI thread.
diff --git a/chrome/browser/safe_browsing/local_database_manager.cc b/chrome/browser/safe_browsing/local_database_manager.cc index 7259e6b5..6607ed4d8 100644 --- a/chrome/browser/safe_browsing/local_database_manager.cc +++ b/chrome/browser/safe_browsing/local_database_manager.cc
@@ -557,6 +557,14 @@ return false; } +bool LocalSafeBrowsingDatabaseManager::CheckUrlForSubresourceFilter( + const GURL& url, + Client* client) { + // TODO(melandory): implement Android support. + NOTREACHED(); + return true; +} + void LocalSafeBrowsingDatabaseManager::CancelCheck(Client* client) { DCHECK_CURRENTLY_ON(BrowserThread::IO); for (const auto& check : checks_) {
diff --git a/chrome/browser/safe_browsing/local_database_manager.h b/chrome/browser/safe_browsing/local_database_manager.h index c03fff31..148f6a7 100644 --- a/chrome/browser/safe_browsing/local_database_manager.h +++ b/chrome/browser/safe_browsing/local_database_manager.h
@@ -116,6 +116,7 @@ bool CanCheckUrl(const GURL& url) const override; bool CheckBrowseUrl(const GURL& url, Client* client) override; + bool CheckUrlForSubresourceFilter(const GURL& url, Client* client) override; bool CheckDownloadUrl(const std::vector<GURL>& url_chain, Client* client) override; bool CheckExtensionIDs(const std::set<std::string>& extension_ids,
diff --git a/chrome/browser/safe_browsing/srt_fetcher_browsertest_win.cc b/chrome/browser/safe_browsing/srt_fetcher_browsertest_win.cc index 1d29cb9..0140984 100644 --- a/chrome/browser/safe_browsing/srt_fetcher_browsertest_win.cc +++ b/chrome/browser/safe_browsing/srt_fetcher_browsertest_win.cc
@@ -597,4 +597,42 @@ EXPECT_EQ(last_time_sent_logs, GetLastTimeSentReport()); } +IN_PROC_BROWSER_TEST_F(SRTFetcherTest, ReporterLogging_MultipleLaunches) { + exit_code_to_report_ = kSwReporterNothingFound; + base::test::ScopedFeatureList scoped_feature_list; + EnableSBExtendedReporting(); + SetLastTimeSentReport(kDaysBetweenReporterLogsSent + 3); + + const base::FilePath path1(L"path1"); + const base::FilePath path2(L"path2"); + SwReporterQueue invocations; + for (const auto& path : {path1, path2}) { + auto invocation = SwReporterInvocation::FromFilePath(path); + invocation.supported_behaviours = + SwReporterInvocation::BEHAVIOUR_ALLOW_SEND_REPORTER_LOGS; + invocations.push(invocation); + } + RunReporterQueue(invocations); + + // SBER is enabled and last time logs were sent was more than + // |kDaysBetweenReporterLogsSent| day ago, so we should send logs in this run. + { + SCOPED_TRACE("first launch"); + TestPartialLaunchCycle({path1}); + ExpectLoggingSwitches(std::set<std::string>(std::begin(kExpectedSwitches), + std::end(kExpectedSwitches))); + ExpectLastReportSentInTheLastHour(); + } + + // Logs should also be sent for the next run, even though LastTimeSentReport + // is now recent, because the run is part of the same set of invocations. + { + SCOPED_TRACE("second launch"); + TestReporterLaunchCycle({path2}); + ExpectLoggingSwitches(std::set<std::string>(std::begin(kExpectedSwitches), + std::end(kExpectedSwitches))); + ExpectLastReportSentInTheLastHour(); + } +} + } // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/srt_fetcher_win.cc b/chrome/browser/safe_browsing/srt_fetcher_win.cc index ac6021b6..6a3ca19 100644 --- a/chrome/browser/safe_browsing/srt_fetcher_win.cc +++ b/chrome/browser/safe_browsing/srt_fetcher_win.cc
@@ -913,6 +913,19 @@ // Also make sure the kSwReporterLastTimeTriggered value is not set in // the future. last_time_triggered > now)) { + const base::Time last_time_sent_logs = base::Time::FromInternalValue( + local_state->GetInt64(prefs::kSwReporterLastTimeSentReport)); + const base::Time next_time_send_logs = + last_time_sent_logs + + base::TimeDelta::FromDays(kDaysBetweenReporterLogsSent); + // Send the logs for this whole queue of invocations if the last send is + // in the future or if logs have been sent at least + // |kSwReporterLastTimeSentReport| days ago. The former is intended as a + // measure for failure recovery, in case the time in local state is + // incorrectly set to the future. + in_logs_upload_period_ = + last_time_sent_logs > now || next_time_send_logs <= now; + DCHECK(current_invocations_.empty()); current_invocations_ = pending_invocations_; ScheduleNextInvocation(); @@ -925,8 +938,8 @@ } // Returns true if the experiment to send reporter logs is enabled, the user - // opted into Safe Browsing extended reporting, and logs have been sent at - // least |kSwReporterLastTimeSentReport| days ago. + // opted into Safe Browsing extended reporting, and this queue of invocations + // started during the logs upload interval. bool ShouldSendReporterLogs(const std::string& suffix, const PrefService& local_state) { UMAHistogramReporter uma(suffix); @@ -934,22 +947,12 @@ uma.RecordLogsUploadEnabled(REPORTER_LOGS_UPLOADS_SBER_DISABLED); return false; } - - const base::Time now = base::Time::Now(); - const base::Time last_time_sent_logs = base::Time::FromInternalValue( - local_state.GetInt64(prefs::kSwReporterLastTimeSentReport)); - const base::Time next_time_send_logs = - last_time_sent_logs + - base::TimeDelta::FromDays(kDaysBetweenReporterLogsSent); - // Send the logs if the last send is the future or if the interval has - // passed. The former is intended as a measure for failure recovery, in - // case the time in local state is incorrectly set to the future. - if (last_time_sent_logs > now || next_time_send_logs <= now) { - uma.RecordLogsUploadEnabled(REPORTER_LOGS_UPLOADS_ENABLED); - return true; + if (!in_logs_upload_period_) { + uma.RecordLogsUploadEnabled(REPORTER_LOGS_UPLOADS_RECENTLY_SENT_LOGS); + return false; } - uma.RecordLogsUploadEnabled(REPORTER_LOGS_UPLOADS_RECENTLY_SENT_LOGS); - return false; + uma.RecordLogsUploadEnabled(REPORTER_LOGS_UPLOADS_ENABLED); + return true; } // Appends switches to the next invocation that depend on the user current @@ -1009,6 +1012,10 @@ // should be run before adding the global error to the Chrome menu. int days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns; + // This will be true if the current queue of invocations started at a time + // when logs should be uploaded. + bool in_logs_upload_period_ = false; + // A single leaky instance. static ReporterRunner* instance_;
diff --git a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc index 6a275d9a..572980d 100644 --- a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc +++ b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc
@@ -383,9 +383,9 @@ // Only load secondary accounts when account consistency is enabled. if (switches::IsEnableAccountConsistency() || account_id == loading_primary_account_id_) { - refresh_tokens_[account_id].reset(new AccountStatus( - signin_error_controller_, account_id, refresh_token)); - FireRefreshTokenAvailable(account_id); + refresh_tokens_[account_id].reset(new AccountStatus( + signin_error_controller_, account_id, refresh_token)); + FireRefreshTokenAvailable(account_id); } else { RevokeCredentialsOnServer(refresh_token); ClearPersistedCredentials(account_id);
diff --git a/chrome/browser/ssl/security_state_tab_helper.cc b/chrome/browser/ssl/security_state_tab_helper.cc index 5c9bde96..7c3c996 100644 --- a/chrome/browser/ssl/security_state_tab_helper.cc +++ b/chrome/browser/ssl/security_state_tab_helper.cc
@@ -183,6 +183,7 @@ case safe_browsing::SB_THREAT_TYPE_EXTENSION: case safe_browsing::SB_THREAT_TYPE_BLACKLISTED_RESOURCE: case safe_browsing::SB_THREAT_TYPE_API_ABUSE: + case safe_browsing::SB_THREAT_TYPE_SUBRESOURCE_FILTER: // These threat types are not currently associated with // interstitials, and thus resources with these threat types are // not ever whitelisted or pending whitelisting.
diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc index 9bbf09a..20fc6186 100644 --- a/chrome/browser/ssl/ssl_browser_tests.cc +++ b/chrome/browser/ssl/ssl_browser_tests.cc
@@ -18,6 +18,7 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/test/histogram_tester.h" +#include "base/test/scoped_feature_list.h" #include "base/test/simple_test_clock.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/default_clock.h" @@ -38,6 +39,7 @@ #include "chrome/browser/ssl/common_name_mismatch_handler.h" #include "chrome/browser/ssl/security_state_tab_helper.h" #include "chrome/browser/ssl/ssl_blocking_page.h" +#include "chrome/browser/ssl/ssl_error_assistant.pb.h" #include "chrome/browser/ssl/ssl_error_handler.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" @@ -84,9 +86,11 @@ #include "content/public/test/test_navigation_observer.h" #include "content/public/test/test_renderer_host.h" #include "content/public/test/test_utils.h" +#include "crypto/sha2.h" #include "net/base/host_port_pair.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" +#include "net/cert/asn1_util.h" #include "net/cert/cert_status_flags.h" #include "net/cert/mock_cert_verifier.h" #include "net/cert/x509_certificate.h" @@ -104,6 +108,10 @@ #include "net/url_request/url_request_job.h" #include "net/url_request/url_request_test_util.h" +#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION) +#include "chrome/browser/ssl/captive_portal_blocking_page.h" +#endif + #if defined(USE_NSS_CERTS) #include "chrome/browser/net/nss_context.h" #include "net/base/crypto_module.h" @@ -226,12 +234,17 @@ // Waits until the interstitial delay timer in SSLErrorHandler is started. void WaitForTimerStarted() { message_loop_runner_->Run(); } + // Returns true if the interstitial delay timer has been started. + bool timer_started() const { return timer_started_; } + private: void OnTimerStarted(content::WebContents* web_contents) { + timer_started_ = true; if (web_contents_ == web_contents) message_loop_runner_->Quit(); } + bool timer_started_ = false; const content::WebContents* web_contents_; SSLErrorHandler::TimerStartedCallback callback_; @@ -273,6 +286,19 @@ return std::string(buffer.data(), buffer.length()); } +// Returns the Sha256 hash of the SPKI of |cert|. +net::HashValue GetSPKIHash(net::X509Certificate* cert) { + std::string der_data; + EXPECT_TRUE( + net::X509Certificate::GetDEREncoded(cert->os_cert_handle(), &der_data)); + base::StringPiece der_bytes(der_data); + base::StringPiece spki_bytes; + EXPECT_TRUE(net::asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes)); + net::HashValue sha256(net::HASH_VALUE_SHA256); + crypto::SHA256HashString(spki_bytes, sha256.data(), crypto::kSHA256Length); + return sha256; +} + } // namespace class SSLUITest : public InProcessBrowserTest { @@ -308,6 +334,16 @@ "https", "localhost", std::move(interceptor)); } + void SetUp() override { + InProcessBrowserTest::SetUp(); + SSLErrorHandler::ResetConfigForTesting(); + } + + void TearDown() override { + SSLErrorHandler::ResetConfigForTesting(); + InProcessBrowserTest::TearDown(); + } + void SetUpCommandLine(base::CommandLine* command_line) override { // Browser will both run and display insecure content. command_line->AppendSwitch(switches::kAllowRunningInsecureContent); @@ -3691,7 +3727,15 @@ } }; -IN_PROC_BROWSER_TEST_F(SSLBlockingPageIDNTest, SSLBlockingPageDecodesIDN) { +// Flaky on mac: https://crbug.com/689846 +#if defined(OS_MACOSX) +#define MAYBE_SSLBlockingPageDecodesIDN DISABLED_SSLBlockingPageDecodesIDN +#else +#define MAYBE_SSLBlockingPageDecodesIDN SSLBlockingPageDecodesIDN +#endif + +IN_PROC_BROWSER_TEST_F(SSLBlockingPageIDNTest, + MAYBE_SSLBlockingPageDecodesIDN) { EXPECT_TRUE(VerifyIDNDecoded()); } @@ -3885,6 +3929,290 @@ ASSERT_TRUE(content::ExecuteScript(tab, "window.open()")); } +// Put captive portal related tests under a different namespace for nicer +// pattern matching. +using SSLUICaptivePortalListTest = SSLUITest; + +#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION) + +// Tests that the captive portal certificate list is not used when the feature +// is disabled via Finch. The list is passed to SSLErrorHandler via a proto. +IN_PROC_BROWSER_TEST_F(SSLUICaptivePortalListTest, + CaptivePortalCertificateList_Disabled) { + base::test::ScopedFeatureList scoped_feature_list; + // Use InitFromCommandLine instead of InitAndDisableFeature to avoid making + // the feature public in SSLErrorHandler header. + scoped_feature_list.InitFromCommandLine( + std::string() /* enabled */, + "CaptivePortalCertificateList" /* disabled */); + + ASSERT_TRUE(https_server_mismatched_.Start()); + base::HistogramTester histograms; + + // Mark the server's cert as a captive portal cert. + const net::HashValue server_spki_hash = + GetSPKIHash(https_server_mismatched_.GetCertificate().get()); + chrome_browser_ssl::SSLErrorAssistantConfig config_proto; + config_proto.add_captive_portal_cert()->set_sha256_hash( + server_spki_hash.ToString()); + SSLErrorHandler::SetErrorAssistantProtoForTesting(config_proto); + + // Navigate to an unsafe page on the server. A normal SSL interstitial should + // be displayed since CaptivePortalCertificateList feature is disabled. + WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); + SSLInterstitialTimerObserver interstitial_timer_observer(tab); + ui_test_utils::NavigateToURL( + browser(), https_server_mismatched_.GetURL("/ssl/blank_page.html")); + content::WaitForInterstitialAttach(tab); + + InterstitialPage* interstitial_page = tab->GetInterstitialPage(); + ASSERT_EQ(SSLBlockingPage::kTypeForTesting, + interstitial_page->GetDelegateForTesting()->GetTypeForTesting()); + EXPECT_TRUE(interstitial_timer_observer.timer_started()); + + // Check that the histogram for the SSL interstitial was recorded. + histograms.ExpectTotalCount(SSLErrorHandler::GetHistogramNameForTesting(), 2); + histograms.ExpectBucketCount(SSLErrorHandler::GetHistogramNameForTesting(), + SSLErrorHandler::HANDLE_ALL, 1); + histograms.ExpectBucketCount( + SSLErrorHandler::GetHistogramNameForTesting(), + SSLErrorHandler::SHOW_SSL_INTERSTITIAL_OVERRIDABLE, 1); + histograms.ExpectBucketCount(SSLErrorHandler::GetHistogramNameForTesting(), + SSLErrorHandler::CAPTIVE_PORTAL_CERT_FOUND, 0); +} + +// Tests that the captive portal certificate list is used when the feature +// is enabled via Finch. The list is passed to SSLErrorHandler via a proto. +IN_PROC_BROWSER_TEST_F(SSLUICaptivePortalListTest, + CaptivePortalCertificateList_Enabled_FromProto) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitFromCommandLine( + "CaptivePortalCertificateList" /* enabled */, + std::string() /* disabled */); + + ASSERT_TRUE(https_server_mismatched_.Start()); + base::HistogramTester histograms; + + // Mark the server's cert as a captive portal cert. + const net::HashValue server_spki_hash = + GetSPKIHash(https_server_mismatched_.GetCertificate().get()); + chrome_browser_ssl::SSLErrorAssistantConfig config_proto; + config_proto.add_captive_portal_cert()->set_sha256_hash( + server_spki_hash.ToString()); + SSLErrorHandler::SetErrorAssistantProtoForTesting(config_proto); + + // Navigate to an unsafe page on the server. The captive portal interstitial + // should be displayed since CaptivePortalCertificateList feature is enabled. + WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); + SSLInterstitialTimerObserver interstitial_timer_observer(tab); + ui_test_utils::NavigateToURL( + browser(), https_server_mismatched_.GetURL("/ssl/blank_page.html")); + content::WaitForInterstitialAttach(tab); + + InterstitialPage* interstitial_page = tab->GetInterstitialPage(); + ASSERT_EQ(CaptivePortalBlockingPage::kTypeForTesting, + interstitial_page->GetDelegateForTesting()->GetTypeForTesting()); + EXPECT_FALSE(interstitial_timer_observer.timer_started()); + + // Check that the histogram for the captive portal cert was recorded. + histograms.ExpectTotalCount(SSLErrorHandler::GetHistogramNameForTesting(), 3); + histograms.ExpectBucketCount(SSLErrorHandler::GetHistogramNameForTesting(), + SSLErrorHandler::HANDLE_ALL, 1); + histograms.ExpectBucketCount( + SSLErrorHandler::GetHistogramNameForTesting(), + SSLErrorHandler::SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE, 1); + histograms.ExpectBucketCount(SSLErrorHandler::GetHistogramNameForTesting(), + SSLErrorHandler::CAPTIVE_PORTAL_CERT_FOUND, 1); +} + +namespace { + +// Test class that mimics a URL request with a certificate whose SPKI hash is in +// ssl_error_assistant.asciipb resource. A better way of testing the SPKI hashes +// inside the resource bundle would be to serve the actual certificate from the +// embedded test server, but the test server can only serve a limited number of +// predefined certificates. +class SSLUICaptivePortalListResourceBundleTest + : public CertVerifierBrowserTest { + public: + SSLUICaptivePortalListResourceBundleTest() + : CertVerifierBrowserTest(), + https_server_(net::EmbeddedTestServer::TYPE_HTTPS), + https_server_mismatched_(net::EmbeddedTestServer::TYPE_HTTPS) { + https_server_.ServeFilesFromSourceDirectory(base::FilePath(kDocRoot)); + + https_server_mismatched_.SetSSLConfig( + net::EmbeddedTestServer::CERT_MISMATCHED_NAME); + https_server_mismatched_.AddDefaultHandlers(base::FilePath(kDocRoot)); + } + + void SetUp() override { + CertVerifierBrowserTest::SetUp(); + SSLErrorHandler::ResetConfigForTesting(); + SetUpCertVerifier(0, net::OK); + } + + void TearDown() override { + SSLErrorHandler::ResetConfigForTesting(); + CertVerifierBrowserTest::TearDown(); + } + + protected: + void SetUpCertVerifier(net::CertStatus cert_status, int net_result) { + scoped_refptr<net::X509Certificate> cert(https_server_.GetCertificate()); + net::CertVerifyResult verify_result; + verify_result.is_issued_by_known_root = + (net_result != net::ERR_CERT_AUTHORITY_INVALID); + verify_result.verified_cert = cert; + verify_result.cert_status = cert_status; + + // Set the SPKI hash to captive-portal.badssl.com leaf certificate. This + // doesn't match the actual cert (ok_cert.pem) but is good enough for + // testing. + net::HashValue hash; + ASSERT_TRUE( + hash.FromString("sha256/fjZPHewEHTrMDX3I1ecEIeoy3WFxHyGplOLv28kIbtI=")); + verify_result.public_key_hashes.push_back(hash); + mock_cert_verifier()->AddResultForCert(cert, verify_result, net_result); + } + + net::EmbeddedTestServer* https_server() { return &https_server_; } + net::EmbeddedTestServer* https_server_mismatched() { + return &https_server_mismatched_; + } + + private: + net::EmbeddedTestServer https_server_; + net::EmbeddedTestServer https_server_mismatched_; +}; + +} // namespace + +// Same as CaptivePortalCertificateList_Enabled_FromProto, but this time the +// cert's SPKI hash is listed in ssl_error_assistant.asciipb. +IN_PROC_BROWSER_TEST_F(SSLUICaptivePortalListResourceBundleTest, + Enabled_FromResource) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitFromCommandLine( + "CaptivePortalCertificateList" /* enabled */, + std::string() /* disabled */); + ASSERT_TRUE(https_server()->Start()); + base::HistogramTester histograms; + + // Mark the server's cert as a captive portal cert. + SetUpCertVerifier(net::CERT_STATUS_COMMON_NAME_INVALID, + net::ERR_CERT_COMMON_NAME_INVALID); + + // Navigate to an unsafe page on the server. The captive portal interstitial + // should be displayed since CaptivePortalCertificateList feature is enabled. + WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); + SSLInterstitialTimerObserver interstitial_timer_observer(tab); + ui_test_utils::NavigateToURL(browser(), https_server()->GetURL("/")); + content::WaitForInterstitialAttach(tab); + + InterstitialPage* interstitial_page = tab->GetInterstitialPage(); + ASSERT_EQ(CaptivePortalBlockingPage::kTypeForTesting, + interstitial_page->GetDelegateForTesting()->GetTypeForTesting()); + EXPECT_FALSE(interstitial_timer_observer.timer_started()); + + // Check that the histogram for the captive portal cert was recorded. + histograms.ExpectTotalCount(SSLErrorHandler::GetHistogramNameForTesting(), 3); + histograms.ExpectBucketCount(SSLErrorHandler::GetHistogramNameForTesting(), + SSLErrorHandler::HANDLE_ALL, 1); + histograms.ExpectBucketCount( + SSLErrorHandler::GetHistogramNameForTesting(), + SSLErrorHandler::SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE, 1); + histograms.ExpectBucketCount(SSLErrorHandler::GetHistogramNameForTesting(), + SSLErrorHandler::CAPTIVE_PORTAL_CERT_FOUND, 1); +} + +// Same as SSLUICaptivePortalNameMismatchTest, but this time the error is +// authority-invalid. Captive portal interstitial should not be shown. +IN_PROC_BROWSER_TEST_F(SSLUICaptivePortalListResourceBundleTest, + Enabled_FromResource_AuthorityInvalid) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitFromCommandLine( + "CaptivePortalCertificateList" /* enabled */, + std::string() /* disabled */); + ASSERT_TRUE(https_server()->Start()); + base::HistogramTester histograms; + + // Set interstitial delay to zero. + SSLErrorHandler::SetInterstitialDelayForTesting(base::TimeDelta()); + // Mark the server's cert as a captive portal cert, but with an + // authority-invalid error. + SetUpCertVerifier(net::CERT_STATUS_AUTHORITY_INVALID, + net::ERR_CERT_AUTHORITY_INVALID); + + // Navigate to an unsafe page on the server. CaptivePortalCertificateList + // feature is enabled but the error is not a name mismatch, so a generic SSL + // interstitial should be displayed. + WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); + SSLInterstitialTimerObserver interstitial_timer_observer(tab); + ui_test_utils::NavigateToURL(browser(), https_server()->GetURL("/")); + content::WaitForInterstitialAttach(tab); + + InterstitialPage* interstitial_page = tab->GetInterstitialPage(); + ASSERT_EQ(SSLBlockingPage::kTypeForTesting, + interstitial_page->GetDelegateForTesting()->GetTypeForTesting()); + EXPECT_TRUE(interstitial_timer_observer.timer_started()); + + // Check that the histogram for the captive portal cert was recorded. + histograms.ExpectTotalCount(SSLErrorHandler::GetHistogramNameForTesting(), 2); + histograms.ExpectBucketCount(SSLErrorHandler::GetHistogramNameForTesting(), + SSLErrorHandler::HANDLE_ALL, 1); + histograms.ExpectBucketCount( + SSLErrorHandler::GetHistogramNameForTesting(), + SSLErrorHandler::SHOW_SSL_INTERSTITIAL_OVERRIDABLE, 1); +} + +#else + +// Tests that the captive portal certificate list is not used when captive +// portal checks are disabled by build, even if the captive portal certificate +// list feature is enabled via Finch. The list is passed to SSLErrorHandler via +// a proto. +IN_PROC_BROWSER_TEST_F(SSLUICaptivePortalListTest, PortalChecksDisabled) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitFromCommandLine( + "CaptivePortalCertificateList" /* enabled */, + std::string() /* disabled */); + + ASSERT_TRUE(https_server_mismatched_.Start()); + base::HistogramTester histograms; + + // Mark the server's cert as a captive portal cert. + const net::HashValue server_spki_hash = + GetSPKIHash(https_server_mismatched_.GetCertificate().get()); + chrome_browser_ssl::SSLErrorAssistantConfig config_proto; + config_proto.add_captive_portal_cert()->set_sha256_hash( + server_spki_hash.ToString()); + SSLErrorHandler::SetErrorAssistantProtoForTesting(config_proto); + + // Navigate to an unsafe page on the server. The captive portal interstitial + // should be displayed since CaptivePortalCertificateList feature is enabled. + WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); + SSLInterstitialTimerObserver interstitial_timer_observer(tab); + ui_test_utils::NavigateToURL( + browser(), https_server_mismatched_.GetURL("/ssl/blank_page.html")); + content::WaitForInterstitialAttach(tab); + + InterstitialPage* interstitial_page = tab->GetInterstitialPage(); + ASSERT_EQ(SSLBlockingPage::kTypeForTesting, + interstitial_page->GetDelegateForTesting()->GetTypeForTesting()); + EXPECT_FALSE(interstitial_timer_observer.timer_started()); + + // Check that the histogram for the captive portal cert was recorded. + histograms.ExpectTotalCount(SSLErrorHandler::GetHistogramNameForTesting(), 2); + histograms.ExpectBucketCount(SSLErrorHandler::GetHistogramNameForTesting(), + SSLErrorHandler::HANDLE_ALL, 1); + histograms.ExpectBucketCount( + SSLErrorHandler::GetHistogramNameForTesting(), + SSLErrorHandler::SHOW_SSL_INTERSTITIAL_OVERRIDABLE, 1); +} + +#endif // BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION) + // TODO(jcampan): more tests to do below. // Visit a page over https that contains a frame with a redirect.
diff --git a/chrome/browser/ssl/ssl_error_assistant.proto b/chrome/browser/ssl/ssl_error_assistant.proto index ca64528e..ba05957c 100644 --- a/chrome/browser/ssl/ssl_error_assistant.proto +++ b/chrome/browser/ssl/ssl_error_assistant.proto
@@ -13,6 +13,8 @@ // with "sha256/" and encoded in base64 (same format as // src/net/http/transport_security_state_static.pins) // Example: sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + // + // NOTE: Only leaf certs must be added here. optional string sha256_hash = 1; }
diff --git a/chrome/browser/ssl/ssl_error_handler.cc b/chrome/browser/ssl/ssl_error_handler.cc index 8ddc06f..5cbf4bec 100644 --- a/chrome/browser/ssl/ssl_error_handler.cc +++ b/chrome/browser/ssl/ssl_error_handler.cc
@@ -5,12 +5,15 @@ #include "chrome/browser/ssl/ssl_error_handler.h" #include <stdint.h> +#include <unordered_set> #include <utility> #include "base/callback_helpers.h" #include "base/feature_list.h" +#include "base/files/file_util.h" #include "base/lazy_instance.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "base/strings/stringprintf.h" #include "base/threading/non_thread_safe.h" @@ -21,22 +24,27 @@ #include "chrome/browser/ssl/bad_clock_blocking_page.h" #include "chrome/browser/ssl/ssl_blocking_page.h" #include "chrome/browser/ssl/ssl_cert_reporter.h" +#include "chrome/browser/ssl/ssl_error_assistant.pb.h" #include "chrome/common/features.h" +#include "chrome/grit/browser_resources.h" #include "components/network_time/network_time_tracker.h" #include "components/ssl_errors/error_classification.h" #include "components/ssl_errors/error_info.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_source.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "net/base/net_errors.h" +#include "ui/base/resource/resource_bundle.h" #if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION) #include "chrome/browser/captive_portal/captive_portal_service.h" #include "chrome/browser/captive_portal/captive_portal_service_factory.h" #include "chrome/browser/captive_portal/captive_portal_tab_helper.h" #include "chrome/browser/ssl/captive_portal_blocking_page.h" +#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.h" #endif namespace { @@ -44,13 +52,14 @@ #if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION) const base::Feature kCaptivePortalInterstitial{ "CaptivePortalInterstitial", base::FEATURE_ENABLED_BY_DEFAULT}; + +const base::Feature kCaptivePortalCertificateList{ + "CaptivePortalCertificateList", base::FEATURE_DISABLED_BY_DEFAULT}; #endif const base::Feature kSSLCommonNameMismatchHandling{ "SSLCommonNameMismatchHandling", base::FEATURE_ENABLED_BY_DEFAULT}; -const char kHistogram[] = "interstitial.ssl_error_handler"; - // Default delay in milliseconds before displaying the SSL interstitial. // This can be changed in tests. // - If there is a name mismatch and a suggested URL available result arrives @@ -60,6 +69,8 @@ // - Otherwise, an SSL interstitial is displayed. const int64_t kInterstitialDelayInMilliseconds = 3000; +const char kHistogram[] = "interstitial.ssl_error_handler"; + // Adds a message to console after navigation commits and then, deletes itself. // Also deletes itself if the navigation is stopped. class CommonNameMismatchRedirectObserver @@ -126,6 +137,28 @@ bool IsCaptivePortalInterstitialEnabled() { return base::FeatureList::IsEnabled(kCaptivePortalInterstitial); } + +// Reads the SSL error assistant configuration from the resource bundle. +bool ReadErrorAssistantProtoFromResourceBundle( + chrome_browser_ssl::SSLErrorAssistantConfig* proto) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(proto); + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + base::StringPiece data = + bundle.GetRawDataResource(IDR_SSL_ERROR_ASSISTANT_PB); + google::protobuf::io::ArrayInputStream stream(data.data(), data.size()); + return proto->ParseFromZeroCopyStream(&stream); +} + +std::unique_ptr<std::unordered_set<std::string>> LoadCaptivePortalCertHashes( + const chrome_browser_ssl::SSLErrorAssistantConfig& proto) { + auto hashes = base::MakeUnique<std::unordered_set<std::string>>(); + for (const chrome_browser_ssl::CaptivePortalCert& cert : + proto.captive_portal_cert()) { + hashes.get()->insert(cert.sha256_hash()); + } + return hashes; +} #endif bool IsSSLCommonNameMismatchHandlingEnabled() { @@ -142,6 +175,15 @@ base::Clock* clock() const; network_time::NetworkTimeTracker* network_time_tracker() const; +#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION) + // Returns true if any of the SHA256 hashes in |ssl_info| is of a captive + // portal certificate. The set of captive portal hashes is loaded on first + // use. + bool IsKnownCaptivePortalCert(const net::SSLInfo& ssl_info); +#endif + + // Testing methods: + void ResetForTesting(); void SetInterstitialDelayForTesting(const base::TimeDelta& delay); void SetTimerStartedCallbackForTesting( SSLErrorHandler::TimerStartedCallback* callback); @@ -149,6 +191,11 @@ void SetNetworkTimeTrackerForTesting( network_time::NetworkTimeTracker* tracker); +#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION) + void SetErrorAssistantProtoForTesting( + const chrome_browser_ssl::SSLErrorAssistantConfig& error_assistant_proto); +#endif + private: base::TimeDelta interstitial_delay_; @@ -161,6 +208,13 @@ base::Clock* testing_clock_ = nullptr; network_time::NetworkTimeTracker* network_time_tracker_ = nullptr; + +#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION) + // SPKI hashes belonging to certs treated as captive portals. Null until the + // first time IsKnownCaptivePortalCert() or SetErrorAssistantProtoForTesting() + // is called. + std::unique_ptr<std::unordered_set<std::string>> captive_portal_spki_hashes_; +#endif }; ConfigSingleton::ConfigSingleton() @@ -187,6 +241,17 @@ return testing_clock_; } +void ConfigSingleton::ResetForTesting() { + interstitial_delay_ = + base::TimeDelta::FromMilliseconds(kInterstitialDelayInMilliseconds); + timer_started_callback_ = nullptr; + network_time_tracker_ = nullptr; + testing_clock_ = nullptr; +#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION) + captive_portal_spki_hashes_.reset(); +#endif +} + void ConfigSingleton::SetInterstitialDelayForTesting( const base::TimeDelta& delay) { interstitial_delay_ = delay; @@ -207,6 +272,36 @@ network_time_tracker_ = tracker; } +#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION) +void ConfigSingleton::SetErrorAssistantProtoForTesting( + const chrome_browser_ssl::SSLErrorAssistantConfig& error_assistant_proto) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(!captive_portal_spki_hashes_); + captive_portal_spki_hashes_ = + LoadCaptivePortalCertHashes(error_assistant_proto); +} + +bool ConfigSingleton::IsKnownCaptivePortalCert(const net::SSLInfo& ssl_info) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (!captive_portal_spki_hashes_) { + chrome_browser_ssl::SSLErrorAssistantConfig proto; + CHECK(ReadErrorAssistantProtoFromResourceBundle(&proto)); + captive_portal_spki_hashes_ = LoadCaptivePortalCertHashes(proto); + } + + for (const net::HashValue& hash_value : ssl_info.public_key_hashes) { + if (hash_value.tag != net::HASH_VALUE_SHA256) { + continue; + } + if (captive_portal_spki_hashes_->find(hash_value.ToString()) != + captive_portal_spki_hashes_->end()) { + return true; + } + } + return false; +} +#endif + class SSLErrorHandlerDelegateImpl : public SSLErrorHandler::Delegate { public: SSLErrorHandlerDelegateImpl( @@ -365,6 +460,11 @@ } // static +void SSLErrorHandler::ResetConfigForTesting() { + g_config.Pointer()->ResetForTesting(); +} + +// static void SSLErrorHandler::SetInterstitialDelayForTesting( const base::TimeDelta& delay) { g_config.Pointer()->SetInterstitialDelayForTesting(delay); @@ -396,6 +496,13 @@ return timer_.IsRunning(); } +void SSLErrorHandler::SetErrorAssistantProtoForTesting( + const chrome_browser_ssl::SSLErrorAssistantConfig& config_proto) { +#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION) + g_config.Pointer()->SetErrorAssistantProtoForTesting(config_proto); +#endif +} + SSLErrorHandler::SSLErrorHandler( std::unique_ptr<Delegate> delegate, content::WebContents* web_contents, @@ -426,6 +533,17 @@ return; } +#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION) + if (base::FeatureList::IsEnabled(kCaptivePortalCertificateList) && + cert_error_ == net::ERR_CERT_COMMON_NAME_INVALID && + g_config.Pointer()->IsKnownCaptivePortalCert(ssl_info_)) { + RecordUMA(CAPTIVE_PORTAL_CERT_FOUND); + ShowCaptivePortalInterstitial( + GURL(captive_portal::CaptivePortalDetector::kDefaultURL)); + return; + } +#endif + std::vector<std::string> dns_names; ssl_info_.cert->GetDNSNames(&dns_names); DCHECK(!dns_names.empty());
diff --git a/chrome/browser/ssl/ssl_error_handler.h b/chrome/browser/ssl/ssl_error_handler.h index bdc443a..80089d737 100644 --- a/chrome/browser/ssl/ssl_error_handler.h +++ b/chrome/browser/ssl/ssl_error_handler.h
@@ -15,6 +15,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ssl/common_name_mismatch_handler.h" #include "chrome/browser/ssl/ssl_cert_reporter.h" +#include "chrome/browser/ssl/ssl_error_assistant.pb.h" #include "components/ssl_errors/error_classification.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" @@ -40,16 +41,17 @@ class NetworkTimeTracker; } -// This class is responsible for deciding what type of interstitial to show for -// an SSL validation error. The display of the interstitial might be delayed by -// a few seconds while trying to determine the cause of the error. During this -// window, the class will: check for a clock error, wait for a name-mismatch -// suggested URL, or wait for a captive portal result to arrive. If there is a -// name mismatch error and a corresponding suggested URL result arrives in this -// window, the user is redirected to the suggested URL. -// Failing that, if a captive portal detected result arrives in the time window, -// a captive portal error page is shown. If none of these potential error -// causes match, an SSL interstitial is shown. +// This class is responsible for deciding what type of interstitial to display +// for an SSL validation error and actually displaying it. The display of the +// interstitial might be delayed by a few seconds while trying to determine the +// cause of the error. During this window, the class will: +// - Check for a clock error +// - Check for a known captive portal certificate SPKI +// - Wait for a name-mismatch suggested URL +// - or Wait for a captive portal result to arrive. +// Based on the result of these checks, SSLErrorHandler will show a customized +// interstitial, redirect to a different suggested URL, or, if all else fails, +// show the normal SSL interstitial. // // This class should only be used on the UI thread because its implementation // uses captive_portal::CaptivePortalService which can only be accessed on the @@ -72,6 +74,7 @@ WWW_MISMATCH_URL_AVAILABLE, WWW_MISMATCH_URL_NOT_AVAILABLE, SHOW_BAD_CLOCK, + CAPTIVE_PORTAL_CERT_FOUND, SSL_ERROR_HANDLER_EVENT_COUNT }; @@ -108,6 +111,7 @@ callback); // Testing methods. + static void ResetConfigForTesting(); static void SetInterstitialDelayForTesting(const base::TimeDelta& delay); // The callback pointer must remain valid for the duration of error handling. static void SetInterstitialTimerStartedCallbackForTesting( @@ -115,7 +119,12 @@ static void SetClockForTesting(base::Clock* testing_clock); static void SetNetworkTimeTrackerForTesting( network_time::NetworkTimeTracker* tracker); + static void SetErrorAssistantProtoForTesting( + const chrome_browser_ssl::SSLErrorAssistantConfig& config_proto); static std::string GetHistogramNameForTesting(); + static void SetErrorAssistantConfig( + std::unique_ptr<chrome_browser_ssl::SSLErrorAssistantConfig> + config_proto); bool IsTimerRunningForTesting() const; protected:
diff --git a/chrome/browser/ssl/ssl_error_handler_unittest.cc b/chrome/browser/ssl/ssl_error_handler_unittest.cc index 680a98a..97e3793b 100644 --- a/chrome/browser/ssl/ssl_error_handler_unittest.cc +++ b/chrome/browser/ssl/ssl_error_handler_unittest.cc
@@ -10,12 +10,14 @@ #include "base/metrics/field_trial.h" #include "base/run_loop.h" #include "base/test/histogram_tester.h" +#include "base/test/scoped_feature_list.h" #include "base/test/simple_test_clock.h" #include "base/test/simple_test_tick_clock.h" #include "base/time/time.h" #include "chrome/browser/captive_portal/captive_portal_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ssl/common_name_mismatch_handler.h" +#include "chrome/browser/ssl/ssl_error_assistant.pb.h" #include "chrome/common/features.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "chrome/test/base/testing_profile.h" @@ -43,6 +45,8 @@ const char kCertDateErrorHistogram[] = "interstitial.ssl_error_handler.cert_date_error_delay"; +const net::SHA256HashValue kCertPublicKeyHashValue = {{0x01, 0x02}}; + // Runs |quit_closure| on the UI thread once a URL request has been // seen. Returns a request that hangs. std::unique_ptr<net::test_server::HttpResponse> WaitForRequest( @@ -187,16 +191,21 @@ } // namespace -class SSLErrorHandlerNameMismatchTest : public ChromeRenderViewHostTestHarness { +template <net::CertStatus cert_status> +class SSLErrorHandlerCertStatusTestBase + : public ChromeRenderViewHostTestHarness { public: - SSLErrorHandlerNameMismatchTest() : field_trial_list_(nullptr) {} + SSLErrorHandlerCertStatusTestBase() : field_trial_list_(nullptr) {} void SetUp() override { ChromeRenderViewHostTestHarness::SetUp(); + SSLErrorHandler::ResetConfigForTesting(); SSLErrorHandler::SetInterstitialDelayForTesting(base::TimeDelta()); ssl_info_.cert = net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem"); - ssl_info_.cert_status = net::CERT_STATUS_COMMON_NAME_INVALID; + ssl_info_.cert_status = cert_status; + ssl_info_.public_key_hashes.push_back( + net::HashValue(kCertPublicKeyHashValue)); delegate_ = new TestSSLErrorHandlerDelegate(profile(), web_contents(), ssl_info_); @@ -218,21 +227,29 @@ void TearDown() override { EXPECT_FALSE(error_handler()->IsTimerRunningForTesting()); error_handler_.reset(nullptr); + SSLErrorHandler::ResetConfigForTesting(); ChromeRenderViewHostTestHarness::TearDown(); } TestSSLErrorHandler* error_handler() { return error_handler_.get(); } TestSSLErrorHandlerDelegate* delegate() { return delegate_; } + const net::SSLInfo& ssl_info() { return ssl_info_; } + private: net::SSLInfo ssl_info_; std::unique_ptr<TestSSLErrorHandler> error_handler_; TestSSLErrorHandlerDelegate* delegate_; base::FieldTrialList field_trial_list_; - DISALLOW_COPY_AND_ASSIGN(SSLErrorHandlerNameMismatchTest); + DISALLOW_COPY_AND_ASSIGN(SSLErrorHandlerCertStatusTestBase); }; +using SSLErrorHandlerNameMismatchTest = + SSLErrorHandlerCertStatusTestBase<net::CERT_STATUS_COMMON_NAME_INVALID>; +using SSLErrorHandlerAuthorityInvalidTest = + SSLErrorHandlerCertStatusTestBase<net::CERT_STATUS_AUTHORITY_INVALID>; + class SSLErrorHandlerDateInvalidTest : public ChromeRenderViewHostTestHarness { public: SSLErrorHandlerDateInvalidTest() @@ -246,6 +263,7 @@ void SetUp() override { ChromeRenderViewHostTestHarness::SetUp(); + SSLErrorHandler::ResetConfigForTesting(); field_trial_test()->SetNetworkQueriesWithVariationsService( false, 0.0, @@ -286,6 +304,7 @@ EXPECT_FALSE(error_handler()->IsTimerRunningForTesting()); error_handler_.reset(nullptr); } + SSLErrorHandler::ResetConfigForTesting(); ChromeRenderViewHostTestHarness::TearDown(); } @@ -679,3 +698,157 @@ // Shut down the server to cancel the pending request. ASSERT_TRUE(test_server()->ShutdownAndWaitUntilComplete()); } + +#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION) + +// Tests that a certificate marked as a known captive portal certificate causes +// the captive portal interstitial to be shown. +TEST_F(SSLErrorHandlerNameMismatchTest, CaptivePortalCertificateList_Enabled) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitFromCommandLine( + "CaptivePortalCertificateList" /* enabled */, "" /* disabled */); + + base::HistogramTester histograms; + + EXPECT_FALSE(error_handler()->IsTimerRunningForTesting()); + EXPECT_EQ(1u, ssl_info().public_key_hashes.size()); + + chrome_browser_ssl::SSLErrorAssistantConfig config_proto; + config_proto.add_captive_portal_cert()->set_sha256_hash( + "sha256/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + config_proto.add_captive_portal_cert()->set_sha256_hash( + ssl_info().public_key_hashes[0].ToString()); + config_proto.add_captive_portal_cert()->set_sha256_hash( + "sha256/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); + SSLErrorHandler::SetErrorAssistantProtoForTesting(config_proto); + + error_handler()->StartHandlingError(); + + // Timer shouldn't start for a known captive portal certificate. + EXPECT_FALSE(error_handler()->IsTimerRunningForTesting()); + EXPECT_FALSE(delegate()->captive_portal_checked()); + EXPECT_FALSE(delegate()->ssl_interstitial_shown()); + EXPECT_TRUE(delegate()->captive_portal_interstitial_shown()); + EXPECT_FALSE(delegate()->suggested_url_checked()); + + // A buggy SSL error handler might have incorrectly started the timer. Run to + // completion to ensure the timer is expired. + base::RunLoop().RunUntilIdle(); + + EXPECT_FALSE(error_handler()->IsTimerRunningForTesting()); + EXPECT_FALSE(delegate()->captive_portal_checked()); + EXPECT_FALSE(delegate()->ssl_interstitial_shown()); + EXPECT_TRUE(delegate()->captive_portal_interstitial_shown()); + EXPECT_FALSE(delegate()->suggested_url_checked()); + + // Check that the histogram for the captive portal cert was recorded. + histograms.ExpectTotalCount(SSLErrorHandler::GetHistogramNameForTesting(), 3); + histograms.ExpectBucketCount(SSLErrorHandler::GetHistogramNameForTesting(), + SSLErrorHandler::HANDLE_ALL, 1); + histograms.ExpectBucketCount( + SSLErrorHandler::GetHistogramNameForTesting(), + SSLErrorHandler::SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE, 1); + histograms.ExpectBucketCount(SSLErrorHandler::GetHistogramNameForTesting(), + SSLErrorHandler::CAPTIVE_PORTAL_CERT_FOUND, 1); +} + +// Tests that a certificate marked as a known captive portal certificate does +// not cause the captive portal interstitial to be shown, if the feature is +// disabled. +TEST_F(SSLErrorHandlerNameMismatchTest, CaptivePortalCertificateList_Disabled) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitFromCommandLine( + "" /* enabled */, "CaptivePortalCertificateList" /* disabled */); + + base::HistogramTester histograms; + + EXPECT_FALSE(error_handler()->IsTimerRunningForTesting()); + EXPECT_EQ(1u, ssl_info().public_key_hashes.size()); + + chrome_browser_ssl::SSLErrorAssistantConfig config_proto; + config_proto.add_captive_portal_cert()->set_sha256_hash( + "sha256/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + config_proto.add_captive_portal_cert()->set_sha256_hash( + ssl_info().public_key_hashes[0].ToString()); + config_proto.add_captive_portal_cert()->set_sha256_hash( + "sha256/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); + SSLErrorHandler::SetErrorAssistantProtoForTesting(config_proto); + + error_handler()->StartHandlingError(); + + // Timer shouldn't start for a known captive portal certificate. + EXPECT_TRUE(error_handler()->IsTimerRunningForTesting()); + EXPECT_TRUE(delegate()->captive_portal_checked()); + EXPECT_FALSE(delegate()->ssl_interstitial_shown()); + EXPECT_FALSE(delegate()->captive_portal_interstitial_shown()); + EXPECT_FALSE(delegate()->suggested_url_checked()); + + // A buggy SSL error handler might have incorrectly started the timer. Run to + // completion to ensure the timer is expired. + base::RunLoop().RunUntilIdle(); + + EXPECT_FALSE(error_handler()->IsTimerRunningForTesting()); + EXPECT_TRUE(delegate()->captive_portal_checked()); + EXPECT_TRUE(delegate()->ssl_interstitial_shown()); + EXPECT_FALSE(delegate()->captive_portal_interstitial_shown()); + EXPECT_FALSE(delegate()->suggested_url_checked()); + + // Check that the histogram for the captive portal cert was recorded. + histograms.ExpectTotalCount(SSLErrorHandler::GetHistogramNameForTesting(), 2); + histograms.ExpectBucketCount(SSLErrorHandler::GetHistogramNameForTesting(), + SSLErrorHandler::HANDLE_ALL, 1); + histograms.ExpectBucketCount( + SSLErrorHandler::GetHistogramNameForTesting(), + SSLErrorHandler::SHOW_SSL_INTERSTITIAL_OVERRIDABLE, 1); +} + +// Tests that an error other than name mismatch does not cause a captive portal +// interstitial to be shown, even if the certificate is marked as a known +// captive portal certificate. +TEST_F(SSLErrorHandlerAuthorityInvalidTest, + CaptivePortalCertificateList_ShouldShowGenericInterstitial) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitFromCommandLine( + "CaptivePortalCertificateList" /* enabled */, "" /* disabled */); + + base::HistogramTester histograms; + + EXPECT_FALSE(error_handler()->IsTimerRunningForTesting()); + EXPECT_EQ(1u, ssl_info().public_key_hashes.size()); + + chrome_browser_ssl::SSLErrorAssistantConfig config_proto; + config_proto.add_captive_portal_cert()->set_sha256_hash( + "sha256/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + config_proto.add_captive_portal_cert()->set_sha256_hash( + ssl_info().public_key_hashes[0].ToString()); + config_proto.add_captive_portal_cert()->set_sha256_hash( + "sha256/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); + SSLErrorHandler::SetErrorAssistantProtoForTesting(config_proto); + + error_handler()->StartHandlingError(); + + // Timer should start for captive portal detection. + EXPECT_TRUE(error_handler()->IsTimerRunningForTesting()); + EXPECT_TRUE(delegate()->captive_portal_checked()); + EXPECT_FALSE(delegate()->ssl_interstitial_shown()); + EXPECT_FALSE(delegate()->captive_portal_interstitial_shown()); + EXPECT_FALSE(delegate()->suggested_url_checked()); + + base::RunLoop().RunUntilIdle(); + + EXPECT_FALSE(error_handler()->IsTimerRunningForTesting()); + EXPECT_TRUE(delegate()->captive_portal_checked()); + EXPECT_TRUE(delegate()->ssl_interstitial_shown()); + EXPECT_FALSE(delegate()->captive_portal_interstitial_shown()); + EXPECT_FALSE(delegate()->suggested_url_checked()); + + // Check that the histogram for the captive portal cert was recorded. + histograms.ExpectTotalCount(SSLErrorHandler::GetHistogramNameForTesting(), 2); + histograms.ExpectBucketCount(SSLErrorHandler::GetHistogramNameForTesting(), + SSLErrorHandler::HANDLE_ALL, 1); + histograms.ExpectBucketCount( + SSLErrorHandler::GetHistogramNameForTesting(), + SSLErrorHandler::SHOW_SSL_INTERSTITIAL_OVERRIDABLE, 1); +} + +#endif // BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
diff --git a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc index 5eb1a17..693ab281 100644 --- a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc +++ b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
@@ -53,7 +53,7 @@ // Names of DocumentLoad histograms. constexpr const char kDocumentLoadActivationLevel[] = - "SubresourceFilter.DocumentLoad.ActivationLevel"; + "SubresourceFilter.DocumentLoad.ActivationState"; constexpr const char kSubresourceLoadsTotal[] = "SubresourceFilter.DocumentLoad.NumSubresourceLoads.Total"; constexpr const char kSubresourceLoadsEvaluated[] = @@ -545,7 +545,7 @@ // The only frames where filtering was (even considered to be) activated // should be the main frame, and the child that was navigated to an HTTP URL. histogram_tester.ExpectUniqueSample( - "SubresourceFilter.DocumentLoad.ActivationLevel", + kDocumentLoadActivationLevel, static_cast<base::Histogram::Sample>(ActivationLevel::ENABLED), 2); }
diff --git a/chrome/browser/task_manager/providers/task.h b/chrome/browser/task_manager/providers/task.h index d112d38..a3e91cee 100644 --- a/chrome/browser/task_manager/providers/task.h +++ b/chrome/browser/task_manager/providers/task.h
@@ -14,7 +14,7 @@ #include "base/process/process_handle.h" #include "base/strings/string16.h" #include "base/time/time.h" -#include "third_party/WebKit/public/web/WebCache.h" +#include "third_party/WebKit/public/platform/WebCache.h" #include "ui/gfx/image/image_skia.h" class Profile;
diff --git a/chrome/browser/task_manager/task_manager_interface.h b/chrome/browser/task_manager/task_manager_interface.h index 30caeca..c4e31c24 100644 --- a/chrome/browser/task_manager/task_manager_interface.h +++ b/chrome/browser/task_manager/task_manager_interface.h
@@ -20,7 +20,7 @@ #include "base/timer/timer.h" #include "chrome/browser/task_manager/providers/task.h" #include "chrome/browser/task_manager/task_manager_observer.h" -#include "third_party/WebKit/public/web/WebCache.h" +#include "third_party/WebKit/public/platform/WebCache.h" #include "ui/gfx/image/image_skia.h" class PrefRegistrySimple;
diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc index c8db967b..b256778 100644 --- a/chrome/browser/themes/browser_theme_pack.cc +++ b/chrome/browser/themes/browser_theme_pack.cc
@@ -48,7 +48,7 @@ // theme packs that aren't int-equal to this. Increment this number if you // change default theme assets or if you need themes to recreate their generated // images (which are cached). -const int kThemePackVersion = 46; +const int kThemePackVersion = 47; // IDs that are in the DataPack won't clash with the positive integer // uint16_t. kHeaderID should always have the maximum value because we want the
diff --git a/chrome/browser/themes/theme_properties.cc b/chrome/browser/themes/theme_properties.cc index dd1d9f4e..e1d3c85 100644 --- a/chrome/browser/themes/theme_properties.cc +++ b/chrome/browser/themes/theme_properties.cc
@@ -24,14 +24,17 @@ // browser_theme_pack.cc. const SkColor kDefaultColorFrame = SkColorSetRGB(0xCC, 0xCC, 0xCC); +const SkColor kDefaultColorFrameInactive = SkColorSetRGB(0xF5, 0xF5, 0xF5); #if defined(OS_MACOSX) const SkColor kDefaultColorFrameIncognito = SkColorSetARGB(0xE6, 0x14, 0x16, 0x18); -const SkColor kDefaultColorFrameIncognitoInactiveMac = +const SkColor kDefaultColorFrameIncognitoInactive = SkColorSetRGB(0x1E, 0x1E, 0x1E); #else const SkColor kDefaultColorFrameIncognito = SkColorSetRGB(0x28, 0x2B, 0x2D); +const SkColor kDefaultColorFrameIncognitoInactive = + SkColorSetRGB(0x38, 0x3B, 0x3D); #endif const SkColor kDefaultColorToolbar = SkColorSetRGB(0xF2, 0xF2, 0xF2); @@ -72,9 +75,9 @@ constexpr color_utils::HSL kDefaultTintButtons = {-1, -1, -1}; constexpr color_utils::HSL kDefaultTintButtonsIncognito = {-1, -1, 0.85}; constexpr color_utils::HSL kDefaultTintFrame = {-1, -1, -1}; -constexpr color_utils::HSL kDefaultTintFrameInactive = {-1, -1, 0.9}; +constexpr color_utils::HSL kDefaultTintFrameInactive = {-1, -1, 0.75}; constexpr color_utils::HSL kDefaultTintFrameIncognito = {-1, 0.2, 0.35}; -constexpr color_utils::HSL kDefaultTintFrameIncognitoInactive = {-1, 0.2, 0.87}; +constexpr color_utils::HSL kDefaultTintFrameIncognitoInactive = {-1, 0.3, 0.6}; constexpr color_utils::HSL kDefaultTintBackgroundTab = {-1, -1, 0.75}; // ---------------------------------------------------------------------------- @@ -221,13 +224,8 @@ case COLOR_FRAME: return otr ? kDefaultColorFrameIncognito : kDefaultColorFrame; case COLOR_FRAME_INACTIVE: -#if defined(OS_MACOSX) - if (otr) - return kDefaultColorFrameIncognitoInactiveMac; -#endif - return color_utils::HSLShift( - GetDefaultColor(ThemeProperties::COLOR_FRAME, otr), - GetDefaultTint(ThemeProperties::TINT_FRAME_INACTIVE, false)); + return otr ? kDefaultColorFrameIncognitoInactive + : kDefaultColorFrameInactive; case COLOR_TOOLBAR: return otr ? kDefaultColorToolbarIncognito : kDefaultColorToolbar; case COLOR_TAB_TEXT:
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 6983749..a682bc1 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1193,6 +1193,7 @@ "//components/web_modal", "//device/bluetooth", "//mash/public/interfaces", + "//ui/vector_icons", ] } @@ -1333,8 +1334,6 @@ "ash/launcher/browser_shortcut_launcher_item_controller.h", "ash/launcher/browser_status_monitor.cc", "ash/launcher/browser_status_monitor.h", - "ash/launcher/chrome_launcher_app_menu_item.cc", - "ash/launcher/chrome_launcher_app_menu_item.h", "ash/launcher/chrome_launcher_app_menu_item_browser.cc", "ash/launcher/chrome_launcher_app_menu_item_browser.h", "ash/launcher/chrome_launcher_app_menu_item_tab.cc", @@ -1359,8 +1358,6 @@ "ash/launcher/extension_launcher_context_menu.h", "ash/launcher/launcher_app_updater.cc", "ash/launcher/launcher_app_updater.h", - "ash/launcher/launcher_application_menu_item_model.cc", - "ash/launcher/launcher_application_menu_item_model.h", "ash/launcher/launcher_context_menu.cc", "ash/launcher/launcher_context_menu.h", "ash/launcher/launcher_controller_helper.cc", @@ -2289,6 +2286,10 @@ "webui/snippets_internals_message_handler.h", "webui/snippets_internals_ui.cc", "webui/snippets_internals_ui.h", + "webui/webapks_handler.cc", + "webui/webapks_handler.h", + "webui/webapks_ui.cc", + "webui/webapks_ui.h", ] if (enable_vr_shell || enable_webvr) { if (enable_vr_shell) {
diff --git a/chrome/browser/ui/DEPS b/chrome/browser/ui/DEPS index 134d371..c56cf4c 100644 --- a/chrome/browser/ui/DEPS +++ b/chrome/browser/ui/DEPS
@@ -5,6 +5,7 @@ "+components/toolbar", "+components/url_formatter", "+components/version_ui", + "+components/webapks_ui", "-chrome/browser/ui/views", "+mash/public/interfaces", ]
diff --git a/chrome/browser/ui/ash/cast_config_client_media_router.cc b/chrome/browser/ui/ash/cast_config_client_media_router.cc index 333ca46..26e7847 100644 --- a/chrome/browser/ui/ash/cast_config_client_media_router.cc +++ b/chrome/browser/ui/ash/cast_config_client_media_router.cc
@@ -95,7 +95,7 @@ : MediaRoutesObserver(GetMediaRouter()), MediaSinksObserver(GetMediaRouter(), media_router::MediaSourceForDesktop(), - GURL(chrome::kChromeUIMediaRouterURL)), + url::Origin(GURL(chrome::kChromeUIMediaRouterURL))), cast_config_client_(cast_config_client) {} CastDeviceCache::~CastDeviceCache() {} @@ -226,7 +226,7 @@ // TODO(imcheng): Pass in tab casting timeout. GetMediaRouter()->CreateRoute( media_router::MediaSourceForDesktop().id(), sink->id, - GURL("http://cros-cast-origin/"), nullptr, + url::Origin(GURL("http://cros-cast-origin/")), nullptr, std::vector<media_router::MediaRouteResponseCallback>(), base::TimeDelta(), false); }
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc index 91e1904..69d32ab 100644 --- a/chrome/browser/ui/ash/chrome_shell_delegate.cc +++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -553,7 +553,7 @@ std::unique_ptr<ash::PaletteDelegate> ChromeShellDelegate::CreatePaletteDelegate() { - return chromeos::PaletteDelegateChromeOS::Create(); + return base::MakeUnique<chromeos::PaletteDelegateChromeOS>(); } ash::SystemTrayDelegate* ChromeShellDelegate::CreateSystemTrayDelegate() {
diff --git a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc index 069d9a3..b42c02a 100644 --- a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc +++ b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc
@@ -6,17 +6,16 @@ #include <stddef.h> +#include "ash/public/cpp/shelf_application_menu_item.h" #include "ash/wm/window_util.h" #include "base/memory/ptr_util.h" #include "chrome/browser/chromeos/arc/arc_support_host.h" #include "chrome/browser/extensions/launch_util.h" #include "chrome/browser/ui/app_list/arc/arc_app_utils.h" #include "chrome/browser/ui/ash/launcher/arc_playstore_shortcut_launcher_item_controller.h" -#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h" -#include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h" #include "chrome/browser/ui/ash/launcher/launcher_context_menu.h" #include "chrome/browser/ui/ash/launcher/launcher_controller_helper.h" #include "chrome/browser/ui/ash/launcher/launcher_item_controller.h" @@ -125,6 +124,29 @@ return ActivateContent(content); } +ash::ShelfItemDelegate::PerformedAction +AppShortcutLauncherItemController::ItemSelected(const ui::Event& event) { + // In case of a keyboard event, we were called by a hotkey. In that case we + // activate the next item in line if an item of our list is already active. + if (event.type() == ui::ET_KEY_RELEASED && AdvanceToNextApp()) + return kExistingWindowActivated; + return Activate(ash::LAUNCH_FROM_UNKNOWN); +} + +ash::ShelfAppMenuItemList AppShortcutLauncherItemController::GetAppMenuItems( + int event_flags) { + ash::ShelfAppMenuItemList items; + std::vector<content::WebContents*> content_list = GetRunningApplications(); + for (size_t i = 0; i < content_list.size(); i++) { + content::WebContents* web_contents = content_list[i]; + gfx::Image app_icon = launcher_controller()->GetAppListIcon(web_contents); + base::string16 title = launcher_controller()->GetAppListTitle(web_contents); + items.push_back(base::MakeUnique<ChromeLauncherAppMenuItemTab>( + title, &app_icon, web_contents)); + } + return items; +} + void AppShortcutLauncherItemController::Close() { // Close all running 'programs' of this type. std::vector<content::WebContents*> content = @@ -140,28 +162,6 @@ } } -ChromeLauncherAppMenuItems -AppShortcutLauncherItemController::GetApplicationList(int event_flags) { - ChromeLauncherAppMenuItems items; - // Add the application name to the menu. - base::string16 app_title = LauncherControllerHelper::GetAppTitle( - launcher_controller()->profile(), app_id()); - items.push_back( - base::MakeUnique<ChromeLauncherAppMenuItem>(app_title, nullptr, false)); - - std::vector<content::WebContents*> content_list = GetRunningApplications(); - - for (size_t i = 0; i < content_list.size(); i++) { - content::WebContents* web_contents = content_list[i]; - // Get the icon. - gfx::Image app_icon = launcher_controller()->GetAppListIcon(web_contents); - base::string16 title = launcher_controller()->GetAppListTitle(web_contents); - items.push_back(base::MakeUnique<ChromeLauncherAppMenuItemTab>( - title, &app_icon, web_contents, i == 0)); - } - return items; -} - std::vector<content::WebContents*> AppShortcutLauncherItemController::GetRunningApplications() { std::vector<content::WebContents*> items; @@ -195,22 +195,6 @@ return items; } -ash::ShelfItemDelegate::PerformedAction -AppShortcutLauncherItemController::ItemSelected(const ui::Event& event) { - // In case of a keyboard event, we were called by a hotkey. In that case we - // activate the next item in line if an item of our list is already active. - if (event.type() == ui::ET_KEY_RELEASED) { - if (AdvanceToNextApp()) - return kExistingWindowActivated; - } - return Activate(ash::LAUNCH_FROM_UNKNOWN); -} - -ui::SimpleMenuModel* AppShortcutLauncherItemController::CreateApplicationMenu( - int event_flags) { - return new LauncherApplicationMenuItemModel(GetApplicationList(event_flags)); -} - content::WebContents* AppShortcutLauncherItemController::GetLRUApplication() { URLPattern refocus_pattern(URLPattern::SCHEME_ALL); refocus_pattern.SetMatchAllURLs(true);
diff --git a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h index 9f2de66f..801c28c 100644 --- a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h +++ b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h
@@ -44,10 +44,9 @@ void Launch(ash::LaunchSource source, int event_flags) override; ash::ShelfItemDelegate::PerformedAction Activate( ash::LaunchSource source) override; - ChromeLauncherAppMenuItems GetApplicationList(int event_flags) override; ash::ShelfItemDelegate::PerformedAction ItemSelected( const ui::Event& event) override; - ui::SimpleMenuModel* CreateApplicationMenu(int event_flags) override; + ash::ShelfAppMenuItemList GetAppMenuItems(int event_flags) override; void Close() override; // Get the refocus url pattern, which can be used to identify this application
diff --git a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc index 92a911c3..a5444c49 100644 --- a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc +++ b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc
@@ -9,7 +9,6 @@ #include "ash/wm/window_util.h" #include "base/memory/ptr_util.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" -#include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h" #include "chrome/browser/ui/ash/launcher/launcher_controller_helper.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" @@ -84,37 +83,6 @@ return kExistingWindowActivated; } -ui::SimpleMenuModel* AppWindowLauncherItemController::CreateApplicationMenu( - int event_flags) { - return new LauncherApplicationMenuItemModel(GetApplicationList(event_flags)); -} - -void AppWindowLauncherItemController::Close() { - // Note: Closing windows may affect the contents of app_windows_. - WindowList windows_to_close = windows_; - for (auto* window : windows_) - window->Close(); -} - -void AppWindowLauncherItemController::ActivateIndexedApp(size_t index) { - if (index >= windows_.size()) - return; - auto it = windows_.begin(); - std::advance(it, index); - ShowAndActivateOrMinimize(*it); -} - -ChromeLauncherAppMenuItems AppWindowLauncherItemController::GetApplicationList( - int event_flags) { - ChromeLauncherAppMenuItems items; - // Add the application name to the menu. - base::string16 app_title = LauncherControllerHelper::GetAppTitle( - launcher_controller()->profile(), app_id()); - items.push_back( - base::MakeUnique<ChromeLauncherAppMenuItem>(app_title, nullptr, false)); - return items; -} - AppWindowLauncherItemController* AppWindowLauncherItemController::AsAppWindowLauncherItemController() { return this; @@ -132,9 +100,29 @@ if (windows_.size() >= 1 && window_to_show->IsActive() && event.type() == ui::ET_KEY_RELEASED) { return ActivateOrAdvanceToNextAppWindow(window_to_show); - } else { - return ShowAndActivateOrMinimize(window_to_show); } + + return ShowAndActivateOrMinimize(window_to_show); +} + +ash::ShelfAppMenuItemList AppWindowLauncherItemController::GetAppMenuItems( + int event_flags) { + return ash::ShelfAppMenuItemList(); +} + +void AppWindowLauncherItemController::Close() { + // Note: Closing windows may affect the contents of app_windows_. + WindowList windows_to_close = windows_; + for (auto* window : windows_) + window->Close(); +} + +void AppWindowLauncherItemController::ActivateIndexedApp(size_t index) { + if (index >= windows_.size()) + return; + auto it = windows_.begin(); + std::advance(it, index); + ShowAndActivateOrMinimize(*it); } void AppWindowLauncherItemController::OnWindowPropertyChanged( @@ -159,7 +147,7 @@ ui::BaseWindow* app_window) { // Either show or minimize windows when shown from the launcher. return launcher_controller()->ActivateWindowOrMinimizeIfActive( - app_window, GetApplicationList(0).size() == 2); + app_window, GetAppMenuItems(0).size() == 1); } ash::ShelfItemDelegate::PerformedAction
diff --git a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h index a5911024..5650cbc8 100644 --- a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h +++ b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h
@@ -46,11 +46,10 @@ void Launch(ash::LaunchSource source, int event_flags) override; ash::ShelfItemDelegate::PerformedAction Activate( ash::LaunchSource source) override; - ChromeLauncherAppMenuItems GetApplicationList(int event_flags) override; AppWindowLauncherItemController* AsAppWindowLauncherItemController() override; ash::ShelfItemDelegate::PerformedAction ItemSelected( const ui::Event& event) override; - ui::SimpleMenuModel* CreateApplicationMenu(int event_flags) override; + ash::ShelfAppMenuItemList GetAppMenuItems(int event_flags) override; void Close() override; // aura::WindowObserver overrides:
diff --git a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.cc index ff829480..f16a57b 100644 --- a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.cc +++ b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.cc
@@ -37,9 +37,9 @@ return ash::ShelfItemDelegate::kNoAction; } -ui::SimpleMenuModel* -ArcAppDeferredLauncherItemController::CreateApplicationMenu(int event_flags) { - return nullptr; +ash::ShelfAppMenuItemList ArcAppDeferredLauncherItemController::GetAppMenuItems( + int event_flags) { + return ash::ShelfAppMenuItemList(); } void ArcAppDeferredLauncherItemController::Close() { @@ -54,8 +54,3 @@ ArcAppDeferredLauncherItemController::Activate(ash::LaunchSource source) { return ash::ShelfItemDelegate::kNoAction; } - -ChromeLauncherAppMenuItems -ArcAppDeferredLauncherItemController::GetApplicationList(int event_flags) { - return ChromeLauncherAppMenuItems(); -}
diff --git a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.h index 549a58c3..fce450e 100644 --- a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.h +++ b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.h
@@ -35,14 +35,13 @@ // ash::ShelfItemDelegate ash::ShelfItemDelegate::PerformedAction ItemSelected( const ui::Event& event) override; - ui::SimpleMenuModel* CreateApplicationMenu(int event_flags) override; + ash::ShelfAppMenuItemList GetAppMenuItems(int event_flags) override; void Close() override; // LauncherItemController overrides: void Launch(ash::LaunchSource source, int event_flags) override; ash::ShelfItemDelegate::PerformedAction Activate( ash::LaunchSource source) override; - ChromeLauncherAppMenuItems GetApplicationList(int event_flags) override; private: // The flags of the event that caused the ARC app to be activated. These will
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.cc index 8255135..12da626 100644 --- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.cc +++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.cc
@@ -12,7 +12,6 @@ #include "chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" -#include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h" #include "chrome/browser/ui/ash/launcher/launcher_controller_helper.h" #include "ui/aura/window.h" #include "ui/base/base_window.h" @@ -50,10 +49,9 @@ } } -ChromeLauncherAppMenuItems -ArcAppWindowLauncherItemController::GetApplicationList(int event_flags) { - ChromeLauncherAppMenuItems items = - AppWindowLauncherItemController::GetApplicationList(event_flags); +ash::ShelfAppMenuItemList ArcAppWindowLauncherItemController::GetAppMenuItems( + int event_flags) { + ash::ShelfAppMenuItemList items; base::string16 app_title = LauncherControllerHelper::GetAppTitle( launcher_controller()->profile(), app_id()); for (auto it = windows().begin(); it != windows().end(); ++it) { @@ -64,8 +62,7 @@ items.push_back(base::MakeUnique<ChromeLauncherAppMenuItemV2App>( ((window && !window->GetTitle().empty()) ? window->GetTitle() : app_title), - &image, app_id(), launcher_controller(), i, - i == 0 /* has_leading_separator */)); + &image, app_id(), launcher_controller(), i)); } return items; }
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.h index eac094b1..9f019c2 100644 --- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.h +++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.h
@@ -24,7 +24,7 @@ // LauncherItemController overrides: ash::ShelfItemDelegate::PerformedAction ItemSelected( const ui::Event& event) override; - ChromeLauncherAppMenuItems GetApplicationList(int event_flags) override; + ash::ShelfAppMenuItemList GetAppMenuItems(int event_flags) override; void AddTaskId(int task_id); void RemoveTaskId(int task_id);
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc index 0a4985d..da46397 100644 --- a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc +++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
@@ -11,16 +11,15 @@ #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/common/wm_window_property.h" +#include "ash/public/cpp/shelf_application_menu_item.h" #include "ash/resources/grit/ash_resources.h" #include "ash/wm/window_util.h" #include "base/memory/ptr_util.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h" -#include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h" #include "chrome/browser/ui/ash/launcher/launcher_context_menu.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" @@ -145,22 +144,28 @@ } return launcher_controller()->ActivateWindowOrMinimizeIfActive( - last_browser->window(), GetApplicationList(0).size() == 2); + last_browser->window(), GetAppMenuItems(0).size() == 1); } -void BrowserShortcutLauncherItemController::Close() { - for (auto* browser : GetListOfActiveBrowsers()) - browser->window()->Close(); +ash::ShelfItemDelegate::PerformedAction +BrowserShortcutLauncherItemController::ItemSelected(const ui::Event& event) { + if (event.flags() & ui::EF_CONTROL_DOWN) { + chrome::NewEmptyWindow(launcher_controller()->profile()); + return kNewWindowCreated; + } + + // In case of a keyboard event, we were called by a hotkey. In that case we + // activate the next item in line if an item of our list is already active. + if (event.type() == ui::ET_KEY_RELEASED) + return ActivateOrAdvanceToNextBrowser(); + + return Activate(ash::LAUNCH_FROM_UNKNOWN); } -ChromeLauncherAppMenuItems -BrowserShortcutLauncherItemController::GetApplicationList(int event_flags) { - ChromeLauncherAppMenuItems items; +ash::ShelfAppMenuItemList +BrowserShortcutLauncherItemController::GetAppMenuItems(int event_flags) { + ash::ShelfAppMenuItemList items; bool found_tabbed_browser = false; - // Add the application name to the menu. - base::string16 app_title = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME); - items.push_back( - base::MakeUnique<ChromeLauncherAppMenuItem>(app_title, nullptr, false)); for (auto* browser : GetListOfActiveBrowsers()) { TabStripModel* tab_strip = browser->tab_strip_model(); if (tab_strip->active_index() == -1) @@ -173,7 +178,7 @@ gfx::Image app_icon = GetBrowserListIcon(web_contents); base::string16 title = GetBrowserListTitle(web_contents); items.push_back(base::MakeUnique<ChromeLauncherAppMenuItemBrowser>( - title, &app_icon, browser, items.size() == 1)); + title, &app_icon, browser)); } else { for (int index = 0; index < tab_strip->count(); ++index) { content::WebContents* web_contents = @@ -182,10 +187,8 @@ launcher_controller()->GetAppListIcon(web_contents); base::string16 title = launcher_controller()->GetAppListTitle(web_contents); - // Check if we need to insert a separator in front. - bool leading_separator = !index; items.push_back(base::MakeUnique<ChromeLauncherAppMenuItemTab>( - title, &app_icon, web_contents, leading_separator)); + title, &app_icon, web_contents)); } } } @@ -196,25 +199,9 @@ return items; } -ash::ShelfItemDelegate::PerformedAction -BrowserShortcutLauncherItemController::ItemSelected(const ui::Event& event) { - if (event.flags() & ui::EF_CONTROL_DOWN) { - chrome::NewEmptyWindow(launcher_controller()->profile()); - return kNewWindowCreated; - } - - // In case of a keyboard event, we were called by a hotkey. In that case we - // activate the next item in line if an item of our list is already active. - if (event.type() == ui::ET_KEY_RELEASED) { - return ActivateOrAdvanceToNextBrowser(); - } - - return Activate(ash::LAUNCH_FROM_UNKNOWN); -} - -ui::SimpleMenuModel* -BrowserShortcutLauncherItemController::CreateApplicationMenu(int event_flags) { - return new LauncherApplicationMenuItemModel(GetApplicationList(event_flags)); +void BrowserShortcutLauncherItemController::Close() { + for (auto* browser : GetListOfActiveBrowsers()) + browser->window()->Close(); } bool BrowserShortcutLauncherItemController::IsListOfActiveBrowserEmpty() {
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h index 8195937..d9e00eb 100644 --- a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h +++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h
@@ -46,10 +46,9 @@ void Launch(ash::LaunchSource source, int event_flags) override; ShelfItemDelegate::PerformedAction Activate( ash::LaunchSource source) override; - ChromeLauncherAppMenuItems GetApplicationList(int event_flags) override; ash::ShelfItemDelegate::PerformedAction ItemSelected( const ui::Event& event) override; - ui::SimpleMenuModel* CreateApplicationMenu(int event_flags) override; + ash::ShelfAppMenuItemList GetAppMenuItems(int event_flags) override; void Close() override; private:
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.cc deleted file mode 100644 index 24dae468..0000000 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.cc +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h" - -ChromeLauncherAppMenuItem::ChromeLauncherAppMenuItem(const base::string16 title, - const gfx::Image* icon, - bool has_leading_separator) - : title_(title), - icon_(icon ? gfx::Image(*icon) : gfx::Image()), - has_leading_separator_(has_leading_separator) {} - -ChromeLauncherAppMenuItem::~ChromeLauncherAppMenuItem() {} - -bool ChromeLauncherAppMenuItem::IsEnabled() const { - return false; -} - -void ChromeLauncherAppMenuItem::Execute(int event_flags) {}
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h deleted file mode 100644 index fad9956f..0000000 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h +++ /dev/null
@@ -1,49 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_H_ -#define CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_H_ - -#include "base/macros.h" -#include "base/strings/string16.h" -#include "ui/gfx/image/image.h" - -// A description for a menu item. It contains the menu item description as well -// as the function which gets executed upon menu item click. -class ChromeLauncherAppMenuItem { - public: - // To insert a separator before this item set |has_leading_separator|. - ChromeLauncherAppMenuItem(const base::string16 title, - const gfx::Image* icon, - bool has_leading_separator); - - virtual ~ChromeLauncherAppMenuItem(); - - // Retrieves the title for this menu option. - const base::string16& title() const { return title_; } - - // Retrieves the icon for this menu option. - const gfx::Image& icon() const { return icon_; } - - // Returns true if a separator should be inserted before this item. - bool HasLeadingSeparator() const { return has_leading_separator_; } - - // Returns true if item is enabled. - virtual bool IsEnabled() const; - - // Executes the option. - // |event_flags| are the flags from the event which issued this command. - // It can be used to check additional keyboard modifiers. - virtual void Execute(int event_flags); - - private: - const base::string16 title_; - const gfx::Image icon_; - - // True if the item has a separator in front of it. - const bool has_leading_separator_; - - DISALLOW_COPY_AND_ASSIGN(ChromeLauncherAppMenuItem); -}; -#endif // CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_H_
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc index 55cfb62..c217f9c 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc
@@ -16,10 +16,8 @@ ChromeLauncherAppMenuItemBrowser::ChromeLauncherAppMenuItemBrowser( const base::string16 title, const gfx::Image* icon, - Browser* browser, - bool has_leading_separator) - : ChromeLauncherAppMenuItem(title, icon, has_leading_separator), - browser_(browser) { + Browser* browser) + : ash::ShelfApplicationMenuItem(title, icon), browser_(browser) { DCHECK(browser); registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSING, @@ -28,10 +26,6 @@ ChromeLauncherAppMenuItemBrowser::~ChromeLauncherAppMenuItemBrowser() {} -bool ChromeLauncherAppMenuItemBrowser::IsEnabled() const { - return true; -} - void ChromeLauncherAppMenuItemBrowser::Execute(int event_flags) { if (browser_) { if (event_flags & (ui::EF_SHIFT_DOWN | ui::EF_MIDDLE_MOUSE_BUTTON)) {
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h index eca80ab..f1d70786 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h
@@ -5,27 +5,23 @@ #ifndef CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_BROWSER_H_ #define CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_BROWSER_H_ +#include "ash/public/cpp/shelf_application_menu_item.h" #include "base/macros.h" -#include "base/values.h" -#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" class Browser; -// A menu item controller for a running browser. It gets created when an -// application list gets created. It's main purpose is to add the activation -// method to the |ChromeLauncherAppMenuItem| class. -class ChromeLauncherAppMenuItemBrowser : public content::NotificationObserver, - public ChromeLauncherAppMenuItem { +// A shelf application menu item for a running browser. +class ChromeLauncherAppMenuItemBrowser : public ash::ShelfApplicationMenuItem, + public content::NotificationObserver { public: ChromeLauncherAppMenuItemBrowser(const base::string16 title, const gfx::Image* icon, - Browser* browser, - bool has_leading_separator); + Browser* browser); ~ChromeLauncherAppMenuItemBrowser() override; - bool IsEnabled() const override; + // ash::ShelfApplicationMenuItem: void Execute(int event_flags) override; private:
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc index e563f24..956b621 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc
@@ -15,15 +15,9 @@ ChromeLauncherAppMenuItemTab::ChromeLauncherAppMenuItemTab( const base::string16 title, const gfx::Image* icon, - content::WebContents* content, - bool has_leading_separator) - : ChromeLauncherAppMenuItem(title, icon, has_leading_separator), - content::WebContentsObserver(content) { -} - -bool ChromeLauncherAppMenuItemTab::IsEnabled() const { - return true; -} + content::WebContents* content) + : ash::ShelfApplicationMenuItem(title, icon), + content::WebContentsObserver(content) {} void ChromeLauncherAppMenuItemTab::Execute(int event_flags) { if (!web_contents())
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h index 699e5d4..00e8336 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h
@@ -5,27 +5,24 @@ #ifndef CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_TAB_H_ #define CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_TAB_H_ +#include "ash/public/cpp/shelf_application_menu_item.h" #include "base/macros.h" #include "base/strings/string16.h" -#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h" #include "content/public/browser/web_contents_observer.h" namespace content{ class WebContents; } -// A menu item controller for a running browser tab. It gets created when an -// application/tab list gets created. It's main purpose is to add the -// activation method to the |ChromeLauncherAppMenuItem| class. -class ChromeLauncherAppMenuItemTab - : public ChromeLauncherAppMenuItem, - public content::WebContentsObserver { +// A shelf application menu item for a running browser tab. +class ChromeLauncherAppMenuItemTab : public ash::ShelfApplicationMenuItem, + public content::WebContentsObserver { public: ChromeLauncherAppMenuItemTab(const base::string16 title, const gfx::Image* icon, - content::WebContents* content, - bool has_leading_separator); - bool IsEnabled() const override; + content::WebContents* content); + + // ash::ShelfApplicationMenuItem: void Execute(int event_flags) override; private:
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.cc index 5c61a1f6..bfa30180 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.cc
@@ -11,20 +11,13 @@ const gfx::Image* icon, const std::string& app_id, ChromeLauncherController* launcher_controller, - int app_index, - bool has_leading_separator) - : ChromeLauncherAppMenuItem(title, icon, has_leading_separator), + int app_index) + : ash::ShelfApplicationMenuItem(title, icon), launcher_controller_(launcher_controller), app_id_(app_id), - app_index_(app_index) { -} + app_index_(app_index) {} -ChromeLauncherAppMenuItemV2App::~ChromeLauncherAppMenuItemV2App() { -} - -bool ChromeLauncherAppMenuItemV2App::IsEnabled() const { - return true; -} +ChromeLauncherAppMenuItemV2App::~ChromeLauncherAppMenuItemV2App() {} void ChromeLauncherAppMenuItemV2App::Execute(int event_flags) { // Note: At this time there is only a single app running at any point. as
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h index 47745bc..82f2a82 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h
@@ -7,26 +7,22 @@ #include <string> +#include "ash/public/cpp/shelf_application_menu_item.h" #include "base/macros.h" -#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h" class ChromeLauncherController; -// A menu item controller for a running V2 application. It gets created when an -// application list gets created. It's main purpose is to add the activation -// method to the |ChromeLauncherAppMenuItem| class. -class ChromeLauncherAppMenuItemV2App : public ChromeLauncherAppMenuItem { +// A shelf application menu item for a running V2 application. +class ChromeLauncherAppMenuItemV2App : public ash::ShelfApplicationMenuItem { public: - ChromeLauncherAppMenuItemV2App( - const base::string16 title, - const gfx::Image* icon, - const std::string& app_id, - ChromeLauncherController* launcher_controller, - int app_index, - bool has_leading_separator); + ChromeLauncherAppMenuItemV2App(const base::string16 title, + const gfx::Image* icon, + const std::string& app_id, + ChromeLauncherController* launcher_controller, + int app_index); ~ChromeLauncherAppMenuItemV2App() override; - bool IsEnabled() const override; + // ash::ShelfApplicationMenuItem: void Execute(int event_flags) override; private:
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h index 8d75234..b40a511 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
@@ -11,11 +11,11 @@ #include "ash/common/shelf/shelf_item_delegate.h" #include "ash/common/shelf/shelf_item_types.h" +#include "ash/public/cpp/shelf_application_menu_item.h" #include "ash/public/interfaces/shelf.mojom.h" #include "chrome/browser/ui/app_icon_loader.h" #include "chrome/browser/ui/app_icon_loader_delegate.h" #include "chrome/browser/ui/app_list/app_list_controller_delegate.h" -#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_types.h" #include "chrome/browser/ui/ash/launcher/settings_window_observer.h" #include "mojo/public/cpp/bindings/associated_binding.h" @@ -43,10 +43,6 @@ class BaseWindow; } -// A list of the elements which makes up a simple menu description. -using ChromeLauncherAppMenuItems = - std::vector<std::unique_ptr<ChromeLauncherAppMenuItem>>; - // ChromeLauncherController manages the launcher items needed for content // windows. Launcher items have a type, an optional app id, and a controller. // Implements mojom::ShelfObserver and is a client of mojom::ShelfController. @@ -193,9 +189,8 @@ // Get the list of all running incarnations of this item. // |event_flags| specifies the flags which were set by the event which // triggered this menu generation. It can be used to generate different lists. - virtual ChromeLauncherAppMenuItems GetApplicationList( - const ash::ShelfItem& item, - int event_flags) = 0; + virtual ash::ShelfAppMenuItemList GetAppMenuItems(const ash::ShelfItem& item, + int event_flags) = 0; // Get the list of all tabs which belong to a certain application type. virtual std::vector<content::WebContents*> GetV1ApplicationsFromAppId(
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc index c04792a..6d6f16d 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc
@@ -47,7 +47,6 @@ #include "chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h" #include "chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h" #include "chrome/browser/ui/ash/launcher/browser_status_monitor.h" -#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h" @@ -616,12 +615,12 @@ controller->AdditionalUserAddedToSession(profile); } -ChromeLauncherAppMenuItems ChromeLauncherControllerImpl::GetApplicationList( +ash::ShelfAppMenuItemList ChromeLauncherControllerImpl::GetAppMenuItems( const ash::ShelfItem& item, int event_flags) { LauncherItemController* controller = GetLauncherItemController(item.id); - return controller ? controller->GetApplicationList(event_flags) - : ChromeLauncherAppMenuItems(); + return controller ? controller->GetAppMenuItems(event_flags) + : ash::ShelfAppMenuItemList(); } std::vector<content::WebContents*>
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h index cfb9bb13..871876a 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h
@@ -95,8 +95,8 @@ bool allow_minimize) override; void ActiveUserChanged(const std::string& user_email) override; void AdditionalUserAddedToSession(Profile* profile) override; - ChromeLauncherAppMenuItems GetApplicationList(const ash::ShelfItem& item, - int event_flags) override; + ash::ShelfAppMenuItemList GetAppMenuItems(const ash::ShelfItem& item, + int event_flags) override; std::vector<content::WebContents*> GetV1ApplicationsFromAppId( const std::string& app_id) override; void ActivateShellApp(const std::string& app_id, int window_index) override;
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc index 0f1b8e34..42a4047d 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc
@@ -39,7 +39,6 @@ #include "chrome/browser/ui/ash/app_list/test/app_list_service_ash_test_api.h" #include "chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h" -#include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h" #include "chrome/browser/ui/ash/launcher/launcher_context_menu.h" #include "chrome/browser/ui/ash/launcher/launcher_item_controller.h" #include "chrome/browser/ui/ash/session_controller_client.h" @@ -225,20 +224,6 @@ return controller_->GetLauncherItemController(id); } - // Returns the number of menu items, ignoring separators. - int GetNumApplicationMenuItems(const ash::ShelfItem& item) { - const int event_flags = 0; - std::unique_ptr<ui::SimpleMenuModel> menu( - new LauncherApplicationMenuItemModel( - controller_->GetApplicationList(item, event_flags))); - int num_items = 0; - for (int i = 0; i < menu->GetItemCount(); ++i) { - if (menu->GetTypeAt(i) != ui::MenuModel::TYPE_SEPARATOR) - ++num_items; - } - return num_items; - } - ChromeLauncherControllerImpl* controller_; private: @@ -278,10 +263,9 @@ size_t NumberOfDetectedLauncherBrowsers(bool show_all_tabs) { LauncherItemController* item_controller = controller_->GetBrowserShortcutLauncherItemController(); - int items = item_controller->GetApplicationList( - show_all_tabs ? ui::EF_SHIFT_DOWN : 0).size(); - // If we have at least one item, we have also a title which we remove here. - return items ? (items - 1) : 0; + return item_controller + ->GetAppMenuItems(show_all_tabs ? ui::EF_SHIFT_DOWN : 0) + .size(); } const Extension* LoadAndLaunchExtension( @@ -551,37 +535,32 @@ IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, MultipleWindows) { int item_count = shelf_model()->item_count(); - // First run app. + // Run the application; a shelf item should be added with one app menu item. const Extension* extension = LoadAndLaunchPlatformApp("launch", "Launched"); AppWindow* window1 = CreateAppWindow(browser()->profile(), extension); - ++item_count; - ASSERT_EQ(item_count, shelf_model()->item_count()); + ASSERT_EQ(item_count + 1, shelf_model()->item_count()); const ash::ShelfItem& item1 = GetLastLauncherItem(); ash::ShelfID item_id = item1.id; EXPECT_EQ(ash::TYPE_APP, item1.type); EXPECT_EQ(ash::STATUS_ACTIVE, item1.status); - EXPECT_EQ(2, GetNumApplicationMenuItems(item1)); // Title + 1 window + EXPECT_EQ(1u, controller_->GetAppMenuItems(item1, 0).size()); // 1 window - // Add second window. + // Add a second window; confirm the shelf item stays; check the app menu. AppWindow* window2 = CreateAppWindow(browser()->profile(), extension); - // Confirm item stays. - ASSERT_EQ(item_count, shelf_model()->item_count()); + ASSERT_EQ(item_count + 1, shelf_model()->item_count()); const ash::ShelfItem& item2 = *shelf_model()->ItemByID(item_id); EXPECT_EQ(ash::STATUS_ACTIVE, item2.status); - EXPECT_EQ(3, GetNumApplicationMenuItems(item2)); // Title + 2 windows + EXPECT_EQ(2u, controller_->GetAppMenuItems(item2, 0).size()); // 2 windows - // Close second window. + // Close the second window; confirm the shelf item stays; check the app menu. CloseAppWindow(window2); - // Confirm item stays. - ASSERT_EQ(item_count, shelf_model()->item_count()); + ASSERT_EQ(item_count + 1, shelf_model()->item_count()); const ash::ShelfItem& item3 = *shelf_model()->ItemByID(item_id); EXPECT_EQ(ash::STATUS_ACTIVE, item3.status); - EXPECT_EQ(2, GetNumApplicationMenuItems(item3)); // Title + 1 window + EXPECT_EQ(1u, controller_->GetAppMenuItems(item3, 0).size()); // 1 window - // Close first window. + // Close the first window; the shelf item should be removed. CloseAppWindow(window1); - // Confirm item is removed. - --item_count; ASSERT_EQ(item_count, shelf_model()->item_count()); }
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc index 3276ab1..ef0f41a 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc
@@ -14,6 +14,7 @@ #include <utility> #include <vector> +#include "ash/common/shelf/shelf_application_menu_model.h" #include "ash/common/shelf/shelf_constants.h" #include "ash/common/shelf/shelf_controller.h" #include "ash/common/shelf/shelf_item_types.h" @@ -59,7 +60,6 @@ #include "chrome/browser/ui/ash/launcher/browser_status_monitor.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h" #include "chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.h" -#include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h" #include "chrome/browser/ui/ash/launcher/launcher_controller_helper.h" #include "chrome/browser/ui/ash/launcher/launcher_item_controller.h" #include "chrome/browser/ui/ash/multi_user/multi_user_util.h" @@ -255,7 +255,7 @@ public: TestV2AppLauncherItemController(const std::string& app_id, ChromeLauncherController* controller) - : LauncherItemController(app_id, "", controller) {} + : LauncherItemController(app_id, std::string(), controller) {} ~TestV2AppLauncherItemController() override {} @@ -265,22 +265,19 @@ ash::LaunchSource source) override { return kExistingWindowActivated; } - void Close() override {} ash::ShelfItemDelegate::PerformedAction ItemSelected( const ui::Event& event) override { return kExistingWindowActivated; } - ChromeLauncherAppMenuItems GetApplicationList(int event_flags) override { - ChromeLauncherAppMenuItems items; - items.push_back(base::MakeUnique<ChromeLauncherAppMenuItem>( - base::string16(), nullptr, false)); - items.push_back(base::MakeUnique<ChromeLauncherAppMenuItem>( - base::string16(), nullptr, false)); + ash::ShelfAppMenuItemList GetAppMenuItems(int event_flags) override { + ash::ShelfAppMenuItemList items; + items.push_back( + base::MakeUnique<ash::ShelfApplicationMenuItem>(base::string16())); + items.push_back( + base::MakeUnique<ash::ShelfApplicationMenuItem>(base::string16())); return items; } - ui::SimpleMenuModel* CreateApplicationMenu(int event_flags) override { - return NULL; - } + void Close() override {} private: DISALLOW_COPY_AND_ASSIGN(TestV2AppLauncherItemController); @@ -832,8 +829,6 @@ void EnableArc(bool enable) { enable ? arc_test_.arc_session_manager()->EnableArc() : arc_test_.arc_session_manager()->DisableArc(); - arc_test_.arc_session_manager()->OnSyncedPrefChanged(prefs::kArcEnabled, - false); base::RunLoop().RunUntilIdle(); } @@ -2776,51 +2771,15 @@ EXPECT_EQ(expected_launchers, actual_launchers); } -// Checks the created menus and menu lists for correctness. It uses the given -// |controller| to create the objects for the given |item| and checks the -// found item count against the |expected_items|. The |title| list contains the -// menu titles in the order of their appearance in the menu (not including the -// application name). -bool CheckMenuCreation(ChromeLauncherControllerImpl* controller, - const ash::ShelfItem& item, - size_t expected_items, - base::string16 title[], - bool is_browser) { - ChromeLauncherAppMenuItems items = controller->GetApplicationList(item, 0); - // A new behavior has been added: Only show menus if there is at least one - // item available. - if (expected_items < 1 && is_browser) { - EXPECT_EQ(0u, items.size()); - return items.size() == 0; - } - // There should be one item in there: The title. - EXPECT_EQ(expected_items + 1, items.size()); - EXPECT_FALSE(items[0]->IsEnabled()); - for (size_t i = 0; i < expected_items; i++) { - EXPECT_EQ(title[i], items[1 + i]->title()); - // Check that the first real item has a leading separator. - if (i == 1) - EXPECT_TRUE(items[i]->HasLeadingSeparator()); - else - EXPECT_FALSE(items[i]->HasLeadingSeparator()); - } - - std::unique_ptr<ui::SimpleMenuModel> menu( - new LauncherApplicationMenuItemModel( - controller->GetApplicationList(item, 0))); - // The first element in the menu is a spacing separator. On some systems - // (e.g. Windows) such things do not exist. As such we check the existence - // and adjust dynamically. - int first_item = menu->GetTypeAt(0) == ui::MenuModel::TYPE_SEPARATOR ? 1 : 0; - int expected_menu_items = first_item + - (expected_items ? (expected_items + 3) : 2); - EXPECT_EQ(expected_menu_items, menu->GetItemCount()); - EXPECT_FALSE(menu->IsEnabledAt(first_item)); - if (expected_items) { - EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, - menu->GetTypeAt(first_item + 1)); - } - return items.size() == expected_items + 1; +// Ensure |controller| creates the expected menu items for the given shelf item. +void CheckAppMenu(ChromeLauncherControllerImpl* controller, + const ash::ShelfItem& item, + size_t expected_item_count, + base::string16 expected_item_titles[]) { + ash::ShelfAppMenuItemList items = controller->GetAppMenuItems(item, 0); + ASSERT_EQ(expected_item_count, items.size()); + for (size_t i = 0; i < expected_item_count; i++) + EXPECT_EQ(expected_item_titles[i], items[i]->title()); } // Check that browsers get reflected correctly in the launcher menu. @@ -2835,8 +2794,7 @@ item_browser.type = ash::TYPE_BROWSER_SHORTCUT; item_browser.id = launcher_controller_->GetShelfIDForAppID(extension_misc::kChromeAppId); - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_browser, 0, NULL, true)); + CheckAppMenu(launcher_controller_.get(), item_browser, 0, nullptr); // Now make the created browser() visible by showing its browser window. browser()->window()->Show(); @@ -2844,8 +2802,7 @@ NavigateAndCommitActiveTabWithTitle(browser(), GURL("http://test1"), title1); base::string16 one_menu_item[] = { title1 }; - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_browser, 1, one_menu_item, true)); + CheckAppMenu(launcher_controller_.get(), item_browser, 1, one_menu_item); // Create one more browser/window and check that one more was added. std::unique_ptr<Browser> browser2( @@ -2859,8 +2816,7 @@ // Check that the list contains now two entries - make furthermore sure that // the active item is the first entry. base::string16 two_menu_items[] = {title1, title2}; - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_browser, 2, two_menu_items, true)); + CheckAppMenu(launcher_controller_.get(), item_browser, 2, two_menu_items); // Apparently we have to close all tabs we have. chrome::CloseTab(browser2.get()); @@ -2880,16 +2836,14 @@ // Check that the menu is empty. chrome::NewTab(browser()); - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_browser, 0, NULL, true)); + CheckAppMenu(launcher_controller_.get(), item_browser, 0, nullptr); // Show the created |browser()| by showing its window. browser()->window()->Show(); base::string16 title1 = ASCIIToUTF16("Test1"); NavigateAndCommitActiveTabWithTitle(browser(), GURL("http://test1"), title1); base::string16 one_menu_item1[] = { title1 }; - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_browser, 1, one_menu_item1, true)); + CheckAppMenu(launcher_controller_.get(), item_browser, 1, one_menu_item1); // Create a browser for another user and check that it is not included in the // users running browser list. @@ -2900,20 +2854,17 @@ std::unique_ptr<Browser> browser2( CreateBrowserAndTabWithProfile(profile2, user2, "http://test2")); base::string16 one_menu_item2[] = { ASCIIToUTF16(user2) }; - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_browser, 1, one_menu_item1, true)); + CheckAppMenu(launcher_controller_.get(), item_browser, 1, one_menu_item1); // Switch to the other user and make sure that only that browser window gets // shown. SwitchActiveUser(account_id2); - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_browser, 1, one_menu_item2, true)); + CheckAppMenu(launcher_controller_.get(), item_browser, 1, one_menu_item2); // Transferred browsers of other users should not show up in the list. chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser( browser()->window()->GetNativeWindow(), account_id2); - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_browser, 1, one_menu_item2, true)); + CheckAppMenu(launcher_controller_.get(), item_browser, 1, one_menu_item2); chrome::CloseTab(browser2.get()); } @@ -2950,16 +2901,14 @@ ash::ShelfItem item_gmail; item_gmail.type = ash::TYPE_APP_SHORTCUT; item_gmail.id = gmail_id; - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_gmail, 0, NULL, false)); + CheckAppMenu(launcher_controller_.get(), item_gmail, 0, nullptr); // Set the gmail URL to a new tab. base::string16 title1 = ASCIIToUTF16("Test1"); NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1); base::string16 one_menu_item[] = { title1 }; - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_gmail, 1, one_menu_item, false)); + CheckAppMenu(launcher_controller_.get(), item_gmail, 1, one_menu_item); // Create one empty tab. chrome::NewTab(browser()); @@ -2974,24 +2923,20 @@ base::string16 title3 = ASCIIToUTF16("Test3"); NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title3); base::string16 two_menu_items[] = {title1, title3}; - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_gmail, 2, two_menu_items, false)); + CheckAppMenu(launcher_controller_.get(), item_gmail, 2, two_menu_items); // Even though the item is in the V1 app list, it should also be in the // browser list. base::string16 browser_menu_item[] = {title3}; - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_browser, 1, browser_menu_item, false)); + CheckAppMenu(launcher_controller_.get(), item_browser, 1, browser_menu_item); // Test that closing of (all) the item(s) does work (and all menus get // updated properly). launcher_controller_->Close(item_gmail.id); - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_gmail, 0, NULL, false)); + CheckAppMenu(launcher_controller_.get(), item_gmail, 0, nullptr); base::string16 browser_menu_item2[] = { title2 }; - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_browser, 1, browser_menu_item2, false)); + CheckAppMenu(launcher_controller_.get(), item_browser, 1, browser_menu_item2); } // Check the multi profile case where only user related apps should show up. @@ -3019,16 +2964,14 @@ ash::ShelfItem item_gmail; item_gmail.type = ash::TYPE_APP_SHORTCUT; item_gmail.id = gmail_id; - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_gmail, 0, NULL, false)); + CheckAppMenu(launcher_controller_.get(), item_gmail, 0, nullptr); // Set the gmail URL to a new tab. base::string16 title1 = ASCIIToUTF16("Test1"); NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1); base::string16 one_menu_item[] = { title1 }; - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_gmail, 1, one_menu_item, false)); + CheckAppMenu(launcher_controller_.get(), item_gmail, 1, one_menu_item); // Create a second profile and switch to that user. std::string user2 = "user2"; @@ -3038,19 +2981,15 @@ SwitchActiveUser(account_id2); // No item should have content yet. - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_browser, 0, NULL, true)); - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_gmail, 0, NULL, false)); + CheckAppMenu(launcher_controller_.get(), item_browser, 0, nullptr); + CheckAppMenu(launcher_controller_.get(), item_gmail, 0, nullptr); // Transfer the browser of the first user - it should still not show up. chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser( browser()->window()->GetNativeWindow(), account_id2); - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_browser, 0, NULL, true)); - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_gmail, 0, NULL, false)); + CheckAppMenu(launcher_controller_.get(), item_browser, 0, nullptr); + CheckAppMenu(launcher_controller_.get(), item_gmail, 0, nullptr); } // Check that V2 applications are creating items properly in the launcher when @@ -3284,34 +3223,24 @@ item_gmail.type = ash::TYPE_APP_SHORTCUT; item_gmail.id = gmail_id; base::string16 two_menu_items[] = {title1, title2}; - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_gmail, 2, two_menu_items, false)); + CheckAppMenu(launcher_controller_.get(), item_gmail, 2, two_menu_items); EXPECT_EQ(1, browser()->tab_strip_model()->active_index()); - // Execute the second item in the list (which shouldn't do anything since that - // item is per definition already the active tab). + // Execute the second item in the menu, after the title and two separators, + // this shouldn't do anything since that item is already the active tab. { - std::unique_ptr<ui::SimpleMenuModel> menu( - new LauncherApplicationMenuItemModel( - launcher_controller_->GetApplicationList(item_gmail, 0))); - // The first element in the menu is a spacing separator. On some systems - // (e.g. Windows) such things do not exist. As such we check the existence - // and adjust dynamically. - int first_item = - (menu->GetTypeAt(0) == ui::MenuModel::TYPE_SEPARATOR) ? 1 : 0; - menu->ActivatedAt(first_item + 3); + ash::ShelfApplicationMenuModel menu( + base::string16(), launcher_controller_->GetAppMenuItems(item_gmail, 0)); + menu.ActivatedAt(4); } EXPECT_EQ(1, browser()->tab_strip_model()->active_index()); - // Execute the first item. + // Execute the first item in the menu, after the title and two separators, + // this should activate the other tab. { - std::unique_ptr<ui::SimpleMenuModel> menu( - new LauncherApplicationMenuItemModel( - launcher_controller_->GetApplicationList(item_gmail, 0))); - int first_item = - (menu->GetTypeAt(0) == ui::MenuModel::TYPE_SEPARATOR) ? 1 : 0; - menu->ActivatedAt(first_item + 2); + ash::ShelfApplicationMenuModel menu( + base::string16(), launcher_controller_->GetAppMenuItems(item_gmail, 0)); + menu.ActivatedAt(3); } - // Now the active tab should be the second item. EXPECT_EQ(0, browser()->tab_strip_model()->active_index()); } @@ -3335,22 +3264,21 @@ item_gmail.type = ash::TYPE_APP_SHORTCUT; item_gmail.id = gmail_id; base::string16 two_menu_items[] = {title1, title2}; - EXPECT_TRUE(CheckMenuCreation( - launcher_controller_.get(), item_gmail, 2, two_menu_items, false)); + CheckAppMenu(launcher_controller_.get(), item_gmail, 2, two_menu_items); int tabs = browser()->tab_strip_model()->count(); // Activate the proper tab through the menu item. { - ChromeLauncherAppMenuItems items = - launcher_controller_->GetApplicationList(item_gmail, 0); + ash::ShelfAppMenuItemList items = + launcher_controller_->GetAppMenuItems(item_gmail, 0); items[1]->Execute(0); EXPECT_EQ(tabs, browser()->tab_strip_model()->count()); } // Delete one tab through the menu item. { - ChromeLauncherAppMenuItems items = - launcher_controller_->GetApplicationList(item_gmail, 0); + ash::ShelfAppMenuItemList items = + launcher_controller_->GetAppMenuItems(item_gmail, 0); items[1]->Execute(ui::EF_SHIFT_DOWN); EXPECT_EQ(--tabs, browser()->tab_strip_model()->count()); } @@ -3429,7 +3357,7 @@ ash::ShelfItem item_gmail; item_gmail.type = ash::TYPE_APP_SHORTCUT; item_gmail.id = gmail_id; - EXPECT_EQ(2U, launcher_controller_->GetApplicationList(item_gmail, 0).size()); + EXPECT_EQ(1U, launcher_controller_->GetAppMenuItems(item_gmail, 0).size()); } // Tests that the Gmail extension does not match the offline verison.
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.cc index 286708b9..e51e737c3 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.cc
@@ -181,11 +181,11 @@ NOTIMPLEMENTED(); } -ChromeLauncherAppMenuItems ChromeLauncherControllerMus::GetApplicationList( +ash::ShelfAppMenuItemList ChromeLauncherControllerMus::GetAppMenuItems( const ash::ShelfItem& item, int event_flags) { NOTIMPLEMENTED(); - return ChromeLauncherAppMenuItems(); + return ash::ShelfAppMenuItemList(); } std::vector<content::WebContents*>
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.h index 647297c..2cb2499 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.h +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.h
@@ -54,8 +54,8 @@ bool allow_minimize) override; void ActiveUserChanged(const std::string& user_email) override; void AdditionalUserAddedToSession(Profile* profile) override; - ChromeLauncherAppMenuItems GetApplicationList(const ash::ShelfItem& item, - int event_flags) override; + ash::ShelfAppMenuItemList GetAppMenuItems(const ash::ShelfItem& item, + int event_flags) override; std::vector<content::WebContents*> GetV1ApplicationsFromAppId( const std::string& app_id) override; void ActivateShellApp(const std::string& app_id, int window_index) override;
diff --git a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.cc index 53f4c89..c783d8f 100644 --- a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.cc +++ b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.cc
@@ -8,7 +8,6 @@ #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" #include "base/memory/ptr_util.h" -#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" #include "chrome/browser/ui/ash/launcher/launcher_context_menu.h" @@ -67,21 +66,9 @@ window_to_app_window_[app_window->GetBaseWindow()] = app_window; } -void ExtensionAppWindowLauncherItemController::OnWindowRemoved( - ui::BaseWindow* window) { - WindowToAppWindow::iterator it = window_to_app_window_.find(window); - if (it == window_to_app_window_.end()) { - NOTREACHED(); - return; - } - - window_to_app_window_.erase(it); -} - -ChromeLauncherAppMenuItems -ExtensionAppWindowLauncherItemController::GetApplicationList(int event_flags) { - ChromeLauncherAppMenuItems items = - AppWindowLauncherItemController::GetApplicationList(event_flags); +ash::ShelfAppMenuItemList +ExtensionAppWindowLauncherItemController::GetAppMenuItems(int event_flags) { + ash::ShelfAppMenuItemList items; int index = 0; for (const auto* window : windows()) { extensions::AppWindow* app_window = window_to_app_window_[window]; @@ -99,9 +86,19 @@ items.push_back(base::MakeUnique<ChromeLauncherAppMenuItemV2App>( app_window->GetTitle(), &result, // Will be copied - app_id(), launcher_controller(), index, - index == 0 /* has_leading_separator */)); + app_id(), launcher_controller(), index)); ++index; } return items; } + +void ExtensionAppWindowLauncherItemController::OnWindowRemoved( + ui::BaseWindow* window) { + WindowToAppWindow::iterator it = window_to_app_window_.find(window); + if (it == window_to_app_window_.end()) { + NOTREACHED(); + return; + } + + window_to_app_window_.erase(it); +}
diff --git a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.h index 17825f5..514dbf3 100644 --- a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.h +++ b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.h
@@ -30,7 +30,7 @@ void AddAppWindow(extensions::AppWindow* app_window); // LauncherItemController overrides: - ChromeLauncherAppMenuItems GetApplicationList(int event_flags) override; + ash::ShelfAppMenuItemList GetAppMenuItems(int event_flags) override; protected: // AppWindowLauncherItemController:
diff --git a/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.cc b/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.cc deleted file mode 100644 index 65f4743..0000000 --- a/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.cc +++ /dev/null
@@ -1,86 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h" - -#include <stddef.h> - -#include <utility> - -#include "base/metrics/histogram_macros.h" -#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h" - -namespace { - -const char kNumItemsEnabledHistogramName[] = - "Ash.Shelf.Menu.NumItemsEnabledUponSelection"; - -const char kSelectedMenuItemIndexHistogramName[] = - "Ash.Shelf.Menu.SelectedMenuItemIndex"; - -} // namespace - -LauncherApplicationMenuItemModel::LauncherApplicationMenuItemModel( - ChromeLauncherAppMenuItems item_list) - : ui::SimpleMenuModel(this), launcher_items_(std::move(item_list)) { - Build(); -} - -LauncherApplicationMenuItemModel::~LauncherApplicationMenuItemModel() {} - -bool LauncherApplicationMenuItemModel::IsCommandIdChecked( - int command_id) const { - return false; -} - -bool LauncherApplicationMenuItemModel::IsCommandIdEnabled( - int command_id) const { - DCHECK(command_id < static_cast<int>(launcher_items_.size())); - return launcher_items_[command_id]->IsEnabled(); -} - -void LauncherApplicationMenuItemModel::ExecuteCommand(int command_id, - int event_flags) { - DCHECK(command_id < static_cast<int>(launcher_items_.size())); - launcher_items_[command_id]->Execute(event_flags); - RecordMenuItemSelectedMetrics(command_id, GetNumMenuItemsEnabled()); -} - -void LauncherApplicationMenuItemModel::Build() { - if (launcher_items_.empty()) - return; - - AddSeparator(ui::SPACING_SEPARATOR); - for (size_t i = 0; i < launcher_items_.size(); i++) { - ChromeLauncherAppMenuItem* item = launcher_items_[i].get(); - - // Check for a separator requirement in front of this item. - if (item->HasLeadingSeparator()) - AddSeparator(ui::SPACING_SEPARATOR); - - // The first item is the context menu, the others are the running apps. - AddItem(i, item->title()); - - if (!item->icon().IsEmpty()) - SetIcon(GetIndexOfCommandId(i), item->icon()); - } - AddSeparator(ui::SPACING_SEPARATOR); -} - -int LauncherApplicationMenuItemModel::GetNumMenuItemsEnabled() const { - int num_menu_items_enabled = 0; - for (const auto& menu_item : launcher_items_) { - if (menu_item->IsEnabled()) - ++num_menu_items_enabled; - } - return num_menu_items_enabled; -} - -void LauncherApplicationMenuItemModel::RecordMenuItemSelectedMetrics( - int command_id, - int num_menu_items_enabled) { - UMA_HISTOGRAM_COUNTS_100(kSelectedMenuItemIndexHistogramName, command_id); - UMA_HISTOGRAM_COUNTS_100(kNumItemsEnabledHistogramName, - num_menu_items_enabled); -}
diff --git a/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h b/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h deleted file mode 100644 index ccc8c56e..0000000 --- a/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_ASH_LAUNCHER_LAUNCHER_APPLICATION_MENU_ITEM_MODEL_H_ -#define CHROME_BROWSER_UI_ASH_LAUNCHER_LAUNCHER_APPLICATION_MENU_ITEM_MODEL_H_ - -#include <memory> -#include <vector> - -#include "base/macros.h" -#include "ui/base/models/simple_menu_model.h" - -class ChromeLauncherAppMenuItem; -class LauncherApplicationMenuItemModelTestAPI; - -// A list of the elements which makes up a simple menu description. -using ChromeLauncherAppMenuItems = - std::vector<std::unique_ptr<ChromeLauncherAppMenuItem>>; - -// A menu model that builds the contents of a menu for a launcher item -// containing a list of running applications. -class LauncherApplicationMenuItemModel : public ui::SimpleMenuModel, - public ui::SimpleMenuModel::Delegate { - public: - explicit LauncherApplicationMenuItemModel( - ChromeLauncherAppMenuItems item_list); - ~LauncherApplicationMenuItemModel() override; - - // Overridden from ui::SimpleMenuModel::Delegate: - bool IsCommandIdChecked(int command_id) const override; - bool IsCommandIdEnabled(int command_id) const override; - void ExecuteCommand(int command_id, int event_flags) override; - - private: - friend class LauncherApplicationMenuItemModelTestAPI; - - void Build(); - - // Returns the number of menu items that are enabled. - int GetNumMenuItemsEnabled() const; - - // Records UMA metrics when a menu item is selected. - void RecordMenuItemSelectedMetrics(int command_id, - int num_menu_items_enabled); - - // The list of menu items as returned from the launcher controller. - ChromeLauncherAppMenuItems launcher_items_; - - DISALLOW_COPY_AND_ASSIGN(LauncherApplicationMenuItemModel); -}; - -#endif // CHROME_BROWSER_UI_ASH_LAUNCHER_LAUNCHER_APPLICATION_MENU_ITEM_MODEL_H_
diff --git a/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model_unittest.cc b/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model_unittest.cc deleted file mode 100644 index 4155447..0000000 --- a/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model_unittest.cc +++ /dev/null
@@ -1,109 +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 "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h" - -#include <utility> - -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/test/histogram_tester.h" -#include "chrome/browser/ui/ash/launcher/test/launcher_application_menu_item_model_test_api.h" -#include "chrome/browser/ui/ash/launcher/test/test_chrome_launcher_app_menu_item.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -const char kNumItemsEnabledHistogramName[] = - "Ash.Shelf.Menu.NumItemsEnabledUponSelection"; - -const char kSelectedMenuItemIndexHistogramName[] = - "Ash.Shelf.Menu.SelectedMenuItemIndex"; - -} // namespace - -// Verifies LauncherApplicationMenuItemModel::GetNumMenuItemsEnabled() return -// value when there are zero menu items. -TEST(LauncherApplicationMenuItemModelTest, - VerifyGetNumMenuItemsEnabledWithNoMenuItems) { - ChromeLauncherAppMenuItems menu_items; - LauncherApplicationMenuItemModel menu_model(std::move(menu_items)); - LauncherApplicationMenuItemModelTestAPI menu_model_test_api(&menu_model); - - EXPECT_EQ(0, menu_model_test_api.GetNumMenuItemsEnabled()); -} - -// Verifies LauncherApplicationMenuItemModel::GetNumMenuItemsEnabled() return -// value when there are a mix of enabled and disabled menu items. -TEST(LauncherApplicationMenuItemModelTest, - VerifyGetNumMenuItemsEnabledWithMenuItems) { - ChromeLauncherAppMenuItems menu_items; - - auto enabled_menu_item_1 = base::MakeUnique<TestChromeLauncherAppMenuItem>(); - enabled_menu_item_1->set_is_enabled(true); - - auto enabled_menu_item_2 = base::MakeUnique<TestChromeLauncherAppMenuItem>(); - enabled_menu_item_2->set_is_enabled(true); - - auto enabled_menu_item_3 = base::MakeUnique<TestChromeLauncherAppMenuItem>(); - enabled_menu_item_3->set_is_enabled(true); - - auto disabled_menu_item_1 = base::MakeUnique<TestChromeLauncherAppMenuItem>(); - disabled_menu_item_1->set_is_enabled(false); - - menu_items.push_back(std::move(enabled_menu_item_1)); - menu_items.push_back(std::move(disabled_menu_item_1)); - menu_items.push_back(std::move(enabled_menu_item_2)); - menu_items.push_back(std::move(enabled_menu_item_3)); - - LauncherApplicationMenuItemModel menu_model(std::move(menu_items)); - LauncherApplicationMenuItemModelTestAPI menu_model_test_api(&menu_model); - - EXPECT_EQ(3, menu_model_test_api.GetNumMenuItemsEnabled()); -} - -// Verifies the correct histogram buckets are recorded for -// LauncherApplicationMenuItemModel::RecordMenuItemSelectedMetrics. -TEST(LauncherApplicationMenuItemModelTest, - VerifyHistogramBucketsRecordedByRecordMenuItemSelectedMetrics) { - const int kCommandId = 3; - const int kNumMenuItemsEnabled = 7; - - base::HistogramTester histogram_tester; - - ChromeLauncherAppMenuItems menu_items; - LauncherApplicationMenuItemModel menu_model(std::move(menu_items)); - LauncherApplicationMenuItemModelTestAPI menu_model_test_api(&menu_model); - menu_model_test_api.RecordMenuItemSelectedMetrics(kCommandId, - kNumMenuItemsEnabled); - - histogram_tester.ExpectTotalCount(kNumItemsEnabledHistogramName, 1); - histogram_tester.ExpectBucketCount(kNumItemsEnabledHistogramName, - kNumMenuItemsEnabled, 1); - - histogram_tester.ExpectTotalCount(kSelectedMenuItemIndexHistogramName, 1); - histogram_tester.ExpectBucketCount(kSelectedMenuItemIndexHistogramName, - kCommandId, 1); -} - -// Verify histogram data is recorded when -// LauncherApplicationMenuItemModel::ExecuteCommand is called. -TEST(LauncherApplicationMenuItemModelTest, - VerifyHistogramDataIsRecordedWhenExecuteCommandIsCalled) { - const int kCommandId = 0; - const int kFlags = 0; - - ChromeLauncherAppMenuItems menu_items; - auto menu_item = base::MakeUnique<TestChromeLauncherAppMenuItem>(); - menu_item->set_is_enabled(true); - menu_items.push_back(std::move(menu_item)); - - base::HistogramTester histogram_tester; - - LauncherApplicationMenuItemModel menu_model(std::move(menu_items)); - menu_model.ExecuteCommand(kCommandId, kFlags); - - histogram_tester.ExpectTotalCount(kNumItemsEnabledHistogramName, 1); - histogram_tester.ExpectTotalCount(kSelectedMenuItemIndexHistogramName, 1); -}
diff --git a/chrome/browser/ui/ash/launcher/launcher_item_controller.h b/chrome/browser/ui/ash/launcher/launcher_item_controller.h index 35e62fb..3661e81c 100644 --- a/chrome/browser/ui/ash/launcher/launcher_item_controller.h +++ b/chrome/browser/ui/ash/launcher/launcher_item_controller.h
@@ -16,10 +16,6 @@ class AppWindowLauncherItemController; class ChromeLauncherController; -class ChromeLauncherAppMenuItem; - -using ChromeLauncherAppMenuItems = - std::vector<std::unique_ptr<ChromeLauncherAppMenuItem>>; // LauncherItemController is used by ChromeLauncherController to track one // or more windows associated with a shelf item. @@ -59,9 +55,6 @@ // Returns the action performed by activating the item. virtual PerformedAction Activate(ash::LaunchSource source) = 0; - // Called to retrieve the list of running applications. - virtual ChromeLauncherAppMenuItems GetApplicationList(int event_flags) = 0; - // Returns nullptr if class is not AppWindowLauncherItemController. virtual AppWindowLauncherItemController* AsAppWindowLauncherItemController();
diff --git a/chrome/browser/ui/ash/launcher/test/launcher_application_menu_item_model_test_api.cc b/chrome/browser/ui/ash/launcher/test/launcher_application_menu_item_model_test_api.cc deleted file mode 100644 index 489c333..0000000 --- a/chrome/browser/ui/ash/launcher/test/launcher_application_menu_item_model_test_api.cc +++ /dev/null
@@ -1,26 +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 "chrome/browser/ui/ash/launcher/test/launcher_application_menu_item_model_test_api.h" - -LauncherApplicationMenuItemModelTestAPI:: - LauncherApplicationMenuItemModelTestAPI( - LauncherApplicationMenuItemModel* menu_item_model) - : menu_item_model_(menu_item_model) { -} - -LauncherApplicationMenuItemModelTestAPI:: - ~LauncherApplicationMenuItemModelTestAPI() { -} - -int LauncherApplicationMenuItemModelTestAPI::GetNumMenuItemsEnabled() const { - return menu_item_model_->GetNumMenuItemsEnabled(); -} - -void LauncherApplicationMenuItemModelTestAPI::RecordMenuItemSelectedMetrics( - int command_id, - int num_menu_items_enabled) { - return menu_item_model_->RecordMenuItemSelectedMetrics( - command_id, num_menu_items_enabled); -}
diff --git a/chrome/browser/ui/ash/launcher/test/launcher_application_menu_item_model_test_api.h b/chrome/browser/ui/ash/launcher/test/launcher_application_menu_item_model_test_api.h deleted file mode 100644 index 33a33b5..0000000 --- a/chrome/browser/ui/ash/launcher/test/launcher_application_menu_item_model_test_api.h +++ /dev/null
@@ -1,36 +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 CHROME_BROWSER_UI_ASH_LAUNCHER_TEST_LAUNCHER_APPLICATION_MENU_ITEM_MODEL_TEST_API_H_ -#define CHROME_BROWSER_UI_ASH_LAUNCHER_TEST_LAUNCHER_APPLICATION_MENU_ITEM_MODEL_TEST_API_H_ - -#include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h" -#include "base/macros.h" - -// Test API to provide internal access to a LauncherApplicationMenuItemModel. -class LauncherApplicationMenuItemModelTestAPI { - public: - // Creates a test api to access the internals of the |menu_item_model|. - explicit LauncherApplicationMenuItemModelTestAPI( - LauncherApplicationMenuItemModel* menu_item_model); - ~LauncherApplicationMenuItemModelTestAPI(); - - // Wrapper function for - // LauncherApplicationMenuItemModel::GetNumMenuItemsEnabled. - int GetNumMenuItemsEnabled() const; - - // Wrapper function for - // LauncherApplicationMenuItemModel::RecordMenuItemSelectedMetrics. - void RecordMenuItemSelectedMetrics(int command_id, - int num_menu_items_enabled); - - private: - // The LauncherApplicationMenuItemModel to provide internal access to. - // Not owned. - LauncherApplicationMenuItemModel* menu_item_model_; - - DISALLOW_COPY_AND_ASSIGN(LauncherApplicationMenuItemModelTestAPI); -}; - -#endif // CHROME_BROWSER_UI_ASH_LAUNCHER_TEST_LAUNCHER_APPLICATION_MENU_ITEM_MODEL_TEST_API_H_
diff --git a/chrome/browser/ui/ash/launcher/test/test_chrome_launcher_app_menu_item.cc b/chrome/browser/ui/ash/launcher/test/test_chrome_launcher_app_menu_item.cc deleted file mode 100644 index aee2419..0000000 --- a/chrome/browser/ui/ash/launcher/test/test_chrome_launcher_app_menu_item.cc +++ /dev/null
@@ -1,22 +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 "chrome/browser/ui/ash/launcher/test/test_chrome_launcher_app_menu_item.h" - -#include "base/strings/utf_string_conversions.h" - -TestChromeLauncherAppMenuItem::TestChromeLauncherAppMenuItem() - : ChromeLauncherAppMenuItem(base::ASCIIToUTF16("DummyTitle"), - nullptr, - false) {} - -TestChromeLauncherAppMenuItem::~TestChromeLauncherAppMenuItem() {} - -bool TestChromeLauncherAppMenuItem::IsEnabled() const { - return is_enabled_; -} - -void TestChromeLauncherAppMenuItem::Execute(int event_flags) { - ++execute_count_; -}
diff --git a/chrome/browser/ui/ash/launcher/test/test_chrome_launcher_app_menu_item.h b/chrome/browser/ui/ash/launcher/test/test_chrome_launcher_app_menu_item.h deleted file mode 100644 index ce7a462..0000000 --- a/chrome/browser/ui/ash/launcher/test/test_chrome_launcher_app_menu_item.h +++ /dev/null
@@ -1,35 +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 CHROME_BROWSER_UI_ASH_LAUNCHER_TEST_TEST_CHROME_LAUNCHER_APP_MENU_ITEM_H_ -#define CHROME_BROWSER_UI_ASH_LAUNCHER_TEST_TEST_CHROME_LAUNCHER_APP_MENU_ITEM_H_ - -#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h" - -#include "base/macros.h" - -// A simple test double for a ChromeLauncherAppMenuItem. -class TestChromeLauncherAppMenuItem : public ChromeLauncherAppMenuItem { - public: - TestChromeLauncherAppMenuItem(); - ~TestChromeLauncherAppMenuItem() override; - - void set_is_enabled(bool is_enabled) { is_enabled_ = is_enabled; } - int execute_count() const { return execute_count_; } - - // ChromeLauncherAppMenuItem: - bool IsEnabled() const override; - void Execute(int event_flags) override; - - private: - // Stub return value for the IsEnabled() function. - bool is_enabled_ = false; - - // Tracks how many times the Execute(int) function has been called. - int execute_count_ = 0; - - DISALLOW_COPY_AND_ASSIGN(TestChromeLauncherAppMenuItem); -}; - -#endif // CHROME_BROWSER_UI_ASH_LAUNCHER_TEST_TEST_CHROME_LAUNCHER_APP_MENU_ITEM_H_
diff --git a/chrome/browser/ui/ash/palette_delegate_chromeos.cc b/chrome/browser/ui/ash/palette_delegate_chromeos.cc index 7c923d6..cc6db0d8 100644 --- a/chrome/browser/ui/ash/palette_delegate_chromeos.cc +++ b/chrome/browser/ui/ash/palette_delegate_chromeos.cc
@@ -21,29 +21,17 @@ #include "components/user_manager/user_manager.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_source.h" -#include "ui/events/devices/input_device_manager.h" namespace chromeos { -// static -std::unique_ptr<PaletteDelegateChromeOS> PaletteDelegateChromeOS::Create() { - if (!ash::IsPaletteFeatureEnabled()) - return nullptr; - return base::WrapUnique(new PaletteDelegateChromeOS()); -} - PaletteDelegateChromeOS::PaletteDelegateChromeOS() : weak_factory_(this) { registrar_.Add(this, chrome::NOTIFICATION_SESSION_STARTED, content::NotificationService::AllSources()); registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, content::NotificationService::AllSources()); - - ui::InputDeviceManager::GetInstance()->AddObserver(this); } -PaletteDelegateChromeOS::~PaletteDelegateChromeOS() { - ui::InputDeviceManager::GetInstance()->RemoveObserver(this); -} +PaletteDelegateChromeOS::~PaletteDelegateChromeOS() {} std::unique_ptr<PaletteDelegateChromeOS::EnableListenerSubscription> PaletteDelegateChromeOS::AddPaletteEnableListener( @@ -131,11 +119,6 @@ then.Run(); } -void PaletteDelegateChromeOS::SetStylusStateChangedCallback( - const OnStylusStateChangedCallback& on_stylus_state_changed) { - on_stylus_state_changed_ = on_stylus_state_changed; -} - bool PaletteDelegateChromeOS::ShouldAutoOpenPalette() { if (!profile_) return false; @@ -176,7 +159,4 @@ ash::Shell::GetInstance()->screenshot_controller()->CancelScreenshotSession(); } -void PaletteDelegateChromeOS::OnStylusStateChanged(ui::StylusState state) { - on_stylus_state_changed_.Run(state); -} } // namespace chromeos
diff --git a/chrome/browser/ui/ash/palette_delegate_chromeos.h b/chrome/browser/ui/ash/palette_delegate_chromeos.h index 95acad8..07bed63 100644 --- a/chrome/browser/ui/ash/palette_delegate_chromeos.h +++ b/chrome/browser/ui/ash/palette_delegate_chromeos.h
@@ -15,7 +15,6 @@ #include "base/values.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" -#include "ui/events/devices/input_device_event_observer.h" class PrefChangeRegistrar; class Profile; @@ -28,26 +27,18 @@ // A class which allows the Ash palette to perform chrome actions. class PaletteDelegateChromeOS : public ash::PaletteDelegate, - public ui::InputDeviceEventObserver, public ash::SessionStateObserver, public content::NotificationObserver { public: - // Attempts to create a palette delegate. This will return null if the palette - // feature is not enabled. - static std::unique_ptr<PaletteDelegateChromeOS> Create(); - + PaletteDelegateChromeOS(); ~PaletteDelegateChromeOS() override; private: - PaletteDelegateChromeOS(); - // ash::PaletteDelegate: std::unique_ptr<EnableListenerSubscription> AddPaletteEnableListener( const EnableListener& on_state_changed) override; void CreateNote() override; bool HasNoteApp() override; - void SetStylusStateChangedCallback( - const OnStylusStateChangedCallback& on_stylus_state_changed) override; bool ShouldAutoOpenPalette() override; bool ShouldShowPalette() override; void TakeScreenshot() override; @@ -62,9 +53,6 @@ const content::NotificationSource& source, const content::NotificationDetails& details) override; - // ui::InputDeviceObserver: - void OnStylusStateChanged(ui::StylusState state) override; - // Called when the palette enabled pref has changed. void OnPaletteEnabledPrefChanged(); @@ -72,7 +60,6 @@ void OnPartialScreenshotDone(const base::Closure& then); base::CallbackList<void(bool)> palette_enabled_callback_list_; - OnStylusStateChangedCallback on_stylus_state_changed_; // Unowned pointer to the active profile. Profile* profile_ = nullptr;
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc index e80cd4d..722d71a8 100644 --- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc +++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
@@ -478,6 +478,13 @@ } } +base::string16 SystemTrayDelegateChromeOS::GetIMEManagedMessage() { + auto ime_state = input_method::InputMethodManager::Get()->GetActiveIMEState(); + return ime_state->GetAllowedInputMethods().empty() + ? base::string16() + : l10n_util::GetStringUTF16(IDS_OPTIONS_CONTROLLED_SETTING_POLICY); +} + void SystemTrayDelegateChromeOS::SwitchIME(const std::string& ime_id) { input_method::InputMethodManager::Get() ->GetActiveIMEState()
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.h b/chrome/browser/ui/ash/system_tray_delegate_chromeos.h index 9b75ea67..db7841e 100644 --- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.h +++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.h
@@ -94,6 +94,7 @@ void GetCurrentIME(ash::IMEInfo* info) override; void GetAvailableIMEList(ash::IMEInfoList* list) override; void GetCurrentIMEProperties(ash::IMEPropertyInfoList* list) override; + base::string16 GetIMEManagedMessage() override; void SwitchIME(const std::string& ime_id) override; void ActivateIMEProperty(const std::string& key) override; void ManageBluetoothDevices() override;
diff --git a/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc b/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc index bd4f50e5..eb20ef7 100644 --- a/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc +++ b/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc
@@ -118,23 +118,25 @@ // The tray should be hidden when there are no sinks. EXPECT_FALSE(test_api.IsTrayVisible()); - media_sinks_observer()->OnSinksUpdated(zero_sinks, std::vector<GURL>()); + media_sinks_observer()->OnSinksUpdated(zero_sinks, + std::vector<url::Origin>()); // Flush mojo messages from the chrome object to the ash object. content::RunAllPendingInMessageLoop(); EXPECT_FALSE(test_api.IsTrayVisible()); EXPECT_FALSE(test_api.IsTraySelectViewVisible()); // The tray should be visible with any more than zero sinks. - media_sinks_observer()->OnSinksUpdated(one_sink, std::vector<GURL>()); + media_sinks_observer()->OnSinksUpdated(one_sink, std::vector<url::Origin>()); content::RunAllPendingInMessageLoop(); EXPECT_TRUE(test_api.IsTrayVisible()); - media_sinks_observer()->OnSinksUpdated(two_sinks, std::vector<GURL>()); + media_sinks_observer()->OnSinksUpdated(two_sinks, std::vector<url::Origin>()); content::RunAllPendingInMessageLoop(); EXPECT_TRUE(test_api.IsTrayVisible()); EXPECT_TRUE(test_api.IsTraySelectViewVisible()); // And if all of the sinks go away, it should be hidden again. - media_sinks_observer()->OnSinksUpdated(zero_sinks, std::vector<GURL>()); + media_sinks_observer()->OnSinksUpdated(zero_sinks, + std::vector<url::Origin>()); content::RunAllPendingInMessageLoop(); EXPECT_FALSE(test_api.IsTrayVisible()); EXPECT_FALSE(test_api.IsTraySelectViewVisible()); @@ -152,7 +154,7 @@ // Setup the sinks. const std::vector<media_router::MediaSink> sinks = { MakeSink("remote_sink", "name"), MakeSink("local_sink", "name")}; - media_sinks_observer()->OnSinksUpdated(sinks, std::vector<GURL>()); + media_sinks_observer()->OnSinksUpdated(sinks, std::vector<url::Origin>()); content::RunAllPendingInMessageLoop(); // Create route combinations. More details below.
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc index dcf4247..487248f 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
@@ -464,9 +464,9 @@ if (suggestions_.empty()) return false; int id = suggestions_[0].frontend_id; - return id > 0 || - id == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY || + return id > 0 || id == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY || id == POPUP_ITEM_ID_PASSWORD_ENTRY || + id == POPUP_ITEM_ID_USERNAME_ENTRY || id == POPUP_ITEM_ID_DATALIST_ENTRY || id == POPUP_ITEM_ID_SCAN_CREDIT_CARD; }
diff --git a/chrome/browser/ui/autofill/autofill_popup_layout_model.cc b/chrome/browser/ui/autofill/autofill_popup_layout_model.cc index a6068ec..e4502f0b 100644 --- a/chrome/browser/ui/autofill/autofill_popup_layout_model.cc +++ b/chrome/browser/ui/autofill/autofill_popup_layout_model.cc
@@ -173,11 +173,12 @@ case POPUP_ITEM_ID_SCAN_CREDIT_CARD: case POPUP_ITEM_ID_SEPARATOR: case POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE: - return normal_font_list_; case POPUP_ITEM_ID_TITLE: + case POPUP_ITEM_ID_PASSWORD_ENTRY: + return normal_font_list_; case POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY: case POPUP_ITEM_ID_DATALIST_ENTRY: - case POPUP_ITEM_ID_PASSWORD_ENTRY: + case POPUP_ITEM_ID_USERNAME_ENTRY: return bold_font_list_; } NOTREACHED();
diff --git a/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.mm b/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.mm index 444110b2..47166727 100644 --- a/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.mm +++ b/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.mm
@@ -21,6 +21,7 @@ #import "chrome/browser/ui/cocoa/location_bar/content_setting_decoration.h" #include "chrome/grit/generated_resources.h" #include "components/content_settings/core/browser/host_content_settings_map.h" +#include "content/public/browser/navigation_handle.h" #include "content/public/browser/plugin_service.h" #include "content/public/browser/web_contents_observer.h" #include "skia/ext/skia_utils_mac.h" @@ -187,9 +188,12 @@ protected: // WebContentsObserver: - void DidNavigateMainFrame( - const content::LoadCommittedDetails& details, - const content::FrameNavigateParams& params) override { + void DidFinishNavigation( + content::NavigationHandle* navigation_handle) override { + if (!navigation_handle->IsInMainFrame() || + !navigation_handle->HasCommitted()) { + return; + } // Content settings are based on the main frame, so if it switches then // close up shop. [controller_ closeBubble:nil];
diff --git a/chrome/browser/ui/cocoa/external_protocol_dialog_cocoa.mm b/chrome/browser/ui/cocoa/external_protocol_dialog_cocoa.mm index 6951e76b..8b451e59 100644 --- a/chrome/browser/ui/cocoa/external_protocol_dialog_cocoa.mm +++ b/chrome/browser/ui/cocoa/external_protocol_dialog_cocoa.mm
@@ -97,17 +97,16 @@ content::WebContents* web_contents = tab_util::GetWebContentsByID(render_process_host_id_, routing_id_); + Profile* profile = + Profile::FromBrowserContext(web_contents->GetBrowserContext()); + bool isChecked = [[alert_ suppressionButton] state] == NSOnState; // Set the "don't warn me again" info. - if ([[alert_ suppressionButton] state] == NSOnState) { - Profile* profile = - Profile::FromBrowserContext(web_contents->GetBrowserContext()); - + if (isChecked) ExternalProtocolHandler::SetBlockState(url_.scheme(), blockState, profile); - ExternalProtocolHandler::RecordMetrics(true); - } else { - ExternalProtocolHandler::RecordMetrics(false); - } + + ExternalProtocolHandler::RecordCheckboxStateMetrics(isChecked); + ExternalProtocolHandler::RecordHandleStateMetrics(isChecked, blockState); if (blockState == ExternalProtocolHandler::DONT_BLOCK) { UMA_HISTOGRAM_LONG_TIMES("clickjacking.launch_url",
diff --git a/chrome/browser/ui/cocoa/handoff_active_url_observer.cc b/chrome/browser/ui/cocoa/handoff_active_url_observer.cc index ba154b2..80c38be 100644 --- a/chrome/browser/ui/cocoa/handoff_active_url_observer.cc +++ b/chrome/browser/ui/cocoa/handoff_active_url_observer.cc
@@ -9,6 +9,7 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/cocoa/handoff_active_url_observer_delegate.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "content/public/browser/navigation_handle.h" #include "content/public/browser/web_contents.h" HandoffActiveURLObserver::HandoffActiveURLObserver( @@ -48,9 +49,11 @@ delegate_->HandoffActiveURLChanged(new_contents); } -void HandoffActiveURLObserver::DidNavigateMainFrame( - const content::LoadCommittedDetails& details, - const content::FrameNavigateParams& params) { +void HandoffActiveURLObserver::DidFinishNavigation( + content::NavigationHandle* navigation_handle) { + if (!navigation_handle->IsInMainFrame() || !navigation_handle->HasCommitted()) + return; + delegate_->HandoffActiveURLChanged(web_contents()); }
diff --git a/chrome/browser/ui/cocoa/handoff_active_url_observer.h b/chrome/browser/ui/cocoa/handoff_active_url_observer.h index 9a8dfac..c5c8c47 100644 --- a/chrome/browser/ui/cocoa/handoff_active_url_observer.h +++ b/chrome/browser/ui/cocoa/handoff_active_url_observer.h
@@ -39,9 +39,8 @@ int reason) override; // content::WebContentsObserver - void DidNavigateMainFrame( - const content::LoadCommittedDetails& details, - const content::FrameNavigateParams& params) override; + void DidFinishNavigation( + content::NavigationHandle* navigation_handle) override; // Updates the active browser. void SetActiveBrowser(Browser* active_browser);
diff --git a/chrome/browser/ui/cocoa/notifications/OWNERS b/chrome/browser/ui/cocoa/notifications/OWNERS index 19ce2de..9cb93ff 100644 --- a/chrome/browser/ui/cocoa/notifications/OWNERS +++ b/chrome/browser/ui/cocoa/notifications/OWNERS
@@ -1,3 +1,5 @@ miguelg@chromium.org peter@chromium.org rsesek@chromium.org + +# COMPONENT: UI>Notifications
diff --git a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.h b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.h index d5e1f50..c706514 100644 --- a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.h +++ b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.h
@@ -48,6 +48,7 @@ // current profile. It is set in |showAccountRemovalView| and used in // |removeAccount|. std::string accountIdToRemove_; + NSButton *firstProfileView_; // Active view mode. profiles::BubbleViewMode viewMode_;
diff --git a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm index 00878e59..3f34aeea 100644 --- a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm +++ b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm
@@ -1594,7 +1594,11 @@ showLock = item.signed_in && profiles::IsLockAvailable(browser_->profile()); } else { - [otherProfiles addObject:[self createOtherProfileView:i]]; + NSButton* otherProfileView = [self createOtherProfileView:i]; + if (!firstProfileView_) { + firstProfileView_ = otherProfileView; + } + [otherProfiles addObject:otherProfileView]; } } if (!currentProfileView) // Guest windows don't have an active profile. @@ -2957,4 +2961,12 @@ return incognitoAvailable && !browser_->profile()->IsGuestSession(); } +- (void)showWindow:(id)sender { + [super showWindow:sender]; + NSEvent *event = [[NSApplication sharedApplication] currentEvent]; + if (firstProfileView_ && [event type] == NSKeyDown) { + [[self window] makeFirstResponder:firstProfileView_]; + } +} + @end
diff --git a/chrome/browser/ui/cocoa/task_manager_mac.mm b/chrome/browser/ui/cocoa/task_manager_mac.mm index 5eb832b1..178681ab 100644 --- a/chrome/browser/ui/cocoa/task_manager_mac.mm +++ b/chrome/browser/ui/cocoa/task_manager_mac.mm
@@ -26,7 +26,6 @@ #include "content/public/browser/notification_source.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/l10n/l10n_util_mac.h" -#include "ui/base/material_design/material_design_controller.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia_util_mac.h" @@ -640,18 +639,10 @@ // Declared in browser_dialogs.h. task_manager::TaskManagerTableModel* ShowTaskManager(Browser* browser) { - if (ui::MaterialDesignController::IsSecondaryUiMaterial()) - return chrome::ShowTaskManagerViews(browser); - return task_manager::TaskManagerMac::Show(); } void HideTaskManager() { - if (ui::MaterialDesignController::IsSecondaryUiMaterial()) { - chrome::HideTaskManagerViews(); - return; - } - task_manager::TaskManagerMac::Hide(); }
diff --git a/chrome/browser/ui/libgtkui/gtk_util.cc b/chrome/browser/ui/libgtkui/gtk_util.cc index c6ef9db..0f6144f8 100644 --- a/chrome/browser/ui/libgtkui/gtk_util.cc +++ b/chrome/browser/ui/libgtkui/gtk_util.cc
@@ -228,14 +228,16 @@ } SkColor CairoSurface::GetAveragePixelValue(bool only_frame_pixels) { + cairo_surface_flush(surface_); int num_samples = 0; long a = 0, r = 0, g = 0, b = 0; SkColor* data = reinterpret_cast<SkColor*>(cairo_image_surface_get_data(surface_)); int width = cairo_image_surface_get_width(surface_); int height = cairo_image_surface_get_height(surface_); + DCHECK(4 * width == cairo_image_surface_get_stride(surface_)); auto accumulate = [&](int x, int y) mutable { - SkColor color = data[x * width + y]; + SkColor color = data[y * width + x]; int alpha = SkColorGetA(color); a += alpha; r += alpha * SkColorGetR(color); @@ -258,6 +260,8 @@ for (int y = 1; y < height - 1; y++) accumulate(x, y); } + if (a == 0) + return SK_ColorTRANSPARENT; return SkColorSetARGB(a / num_samples, r / a, g / a, b / a); }
diff --git a/chrome/browser/ui/libgtkui/native_theme_gtk3.cc b/chrome/browser/ui/libgtkui/native_theme_gtk3.cc index 18df7f8..8f1a3805 100644 --- a/chrome/browser/ui/libgtkui/native_theme_gtk3.cc +++ b/chrome/browser/ui/libgtkui/native_theme_gtk3.cc
@@ -109,7 +109,7 @@ return GetFgColor("GtkMenu#menu GtkMenuItem#menuitem GtkLabel#label"); case ui::NativeTheme::kColorId_SelectedMenuItemForegroundColor: return GetFgColor( - "GtkMenu#menu GtkMenuItem#menuitem:selected GtkLabel#label"); + "GtkMenu#menu GtkMenuItem#menuitem:hover GtkLabel#label"); case ui::NativeTheme::kColorId_DisabledMenuItemForegroundColor: return GetFgColor( "GtkMenu#menu GtkMenuItem#menuitem:disabled GtkLabel#label");
diff --git a/chrome/browser/ui/task_manager/task_manager_table_model.cc b/chrome/browser/ui/task_manager/task_manager_table_model.cc index 306f1a4..c3ec85b3 100644 --- a/chrome/browser/ui/task_manager/task_manager_table_model.cc +++ b/chrome/browser/ui/task_manager/task_manager_table_model.cc
@@ -25,7 +25,7 @@ #include "components/nacl/common/nacl_switches.h" #include "components/prefs/scoped_user_pref_update.h" #include "content/public/common/result_codes.h" -#include "third_party/WebKit/public/web/WebCache.h" +#include "third_party/WebKit/public/platform/WebCache.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/models/table_model_observer.h" #include "ui/base/text/bytes_formatting.h"
diff --git a/chrome/browser/ui/views/chrome_views_delegate.cc b/chrome/browser/ui/views/chrome_views_delegate.cc index 8eb0a06..960656a 100644 --- a/chrome/browser/ui/views/chrome_views_delegate.cc +++ b/chrome/browser/ui/views/chrome_views_delegate.cc
@@ -542,8 +542,17 @@ } gfx::Insets ChromeViewsDelegate::GetDialogButtonInsets() const { - return gfx::Insets(LayoutDelegate::Get()->GetMetric( - LayoutDelegate::Metric::DIALOG_BUTTON_MARGIN)); + const LayoutDelegate* layout_delegate = LayoutDelegate::Get(); + const int top = layout_delegate->GetMetric( + LayoutDelegate::Metric::DIALOG_BUTTON_TOP_SPACING); + const int margin = layout_delegate->GetMetric( + LayoutDelegate::Metric::DIALOG_BUTTON_MARGIN); + return gfx::Insets(top, margin, margin, margin); +} + +int ChromeViewsDelegate::GetDialogCloseButtonMargin() const { + return LayoutDelegate::Get()->GetMetric( + LayoutDelegate::Metric::DIALOG_CLOSE_BUTTON_MARGIN); } int ChromeViewsDelegate::GetDialogRelatedButtonHorizontalSpacing() const {
diff --git a/chrome/browser/ui/views/chrome_views_delegate.h b/chrome/browser/ui/views/chrome_views_delegate.h index d860f71..d3ad432b 100644 --- a/chrome/browser/ui/views/chrome_views_delegate.h +++ b/chrome/browser/ui/views/chrome_views_delegate.h
@@ -63,6 +63,7 @@ scoped_refptr<base::TaskRunner> GetBlockingPoolTaskRunner() override; gfx::Insets GetDialogButtonInsets() const override; + int GetDialogCloseButtonMargin() const override; int GetDialogRelatedButtonHorizontalSpacing() const override; int GetDialogRelatedControlVerticalSpacing() const override; gfx::Insets GetDialogFrameViewInsets() const override;
diff --git a/chrome/browser/ui/views/download/download_shelf_view.cc b/chrome/browser/ui/views/download/download_shelf_view.cc index dbedfe5..1e119e9 100644 --- a/chrome/browser/ui/views/download/download_shelf_view.cc +++ b/chrome/browser/ui/views/download/download_shelf_view.cc
@@ -30,8 +30,8 @@ #include "ui/base/theme_provider.h" #include "ui/gfx/animation/slide_animation.h" #include "ui/gfx/canvas.h" -#include "ui/gfx/vector_icons_public.h" #include "ui/resources/grit/ui_resources.h" +#include "ui/vector_icons/vector_icons.h" #include "ui/views/background.h" #include "ui/views/border.h" #include "ui/views/controls/button/md_text_button.h" @@ -113,7 +113,7 @@ AddChildView(show_all_view_); views::VectorIconButton* close_button = new views::VectorIconButton(this); - close_button->SetIcon(gfx::VectorIconId::BAR_CLOSE); + close_button->SetIcon(ui::kCloseIcon); close_button_ = close_button; close_button_->SetAccessibleName( l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE));
diff --git a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc index 91bba25..2dd4414 100644 --- a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc +++ b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
@@ -934,12 +934,8 @@ { // Verify dragleave DOM event. std::string dragleave_event; - // TODO(paulmeyer): https://crbug.com/669695: Need to unify coordinates - // passed to dragend when OOPIFs are present or not. - state->expected_dom_event_data.set_expected_client_position( - "<no expectation>"); - state->expected_dom_event_data.set_expected_page_position( - "<no expectation>"); + state->expected_dom_event_data.set_expected_client_position("(355, 150)"); + state->expected_dom_event_data.set_expected_page_position("(355, 150)"); EXPECT_TRUE( dragleave_event_waiter.WaitForNextMatchingEvent(&dragleave_event)); @@ -1025,8 +1021,8 @@ state->expected_dom_event_data.set_expected_drop_effect("copy"); state->expected_dom_event_data.set_expected_mime_types(""); - // TODO(paulmeyer): https://crbug.com/669695: Need to unify coordinates - // passed to dragend when OOPIFs are present or not. + // TODO: https://crbug.com/686136: dragEnd coordinates for non-OOPIF + // scenarios are currently broken. state->expected_dom_event_data.set_expected_client_position( "<no expectation>"); state->expected_dom_event_data.set_expected_page_position(
diff --git a/chrome/browser/ui/views/external_protocol_dialog.cc b/chrome/browser/ui/views/external_protocol_dialog.cc index 1feeb32b..2308fcba 100644 --- a/chrome/browser/ui/views/external_protocol_dialog.cc +++ b/chrome/browser/ui/views/external_protocol_dialog.cc
@@ -79,11 +79,12 @@ } bool ExternalProtocolDialog::Cancel() { - delegate_->DoCancel(delegate_->url(), - message_box_view_->IsCheckBoxSelected()); + bool is_checked = message_box_view_->IsCheckBoxSelected(); + delegate_->DoCancel(delegate_->url(), is_checked); - ExternalProtocolHandler::RecordMetrics( - message_box_view_->IsCheckBoxSelected()); + ExternalProtocolHandler::RecordCheckboxStateMetrics(is_checked); + ExternalProtocolHandler::RecordHandleStateMetrics( + is_checked, ExternalProtocolHandler::BLOCK); // Returning true closes the dialog. return true; @@ -96,11 +97,12 @@ UMA_HISTOGRAM_LONG_TIMES("clickjacking.launch_url", base::TimeTicks::Now() - creation_time_); - ExternalProtocolHandler::RecordMetrics( - message_box_view_->IsCheckBoxSelected()); + bool is_checked = message_box_view_->IsCheckBoxSelected(); + ExternalProtocolHandler::RecordCheckboxStateMetrics(is_checked); + ExternalProtocolHandler::RecordHandleStateMetrics( + is_checked, ExternalProtocolHandler::DONT_BLOCK); - delegate_->DoAccept(delegate_->url(), - message_box_view_->IsCheckBoxSelected()); + delegate_->DoAccept(delegate_->url(), is_checked); // Returning true closes the dialog. return true;
diff --git a/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc b/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc index 082dd03..540cb5cb 100644 --- a/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc +++ b/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc
@@ -4,6 +4,8 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" +#include "base/test/histogram_tester.h" +#include "chrome/browser/external_protocol/external_protocol_handler.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/external_protocol_dialog_delegate.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -98,6 +100,8 @@ test::ExternalProtocolDialogTestApi(dialog_).SetCheckBoxSelected(checked); } + base::HistogramTester histogram_tester_; + protected: ExternalProtocolDialog* dialog_ = nullptr; bool called_ = false; @@ -116,6 +120,11 @@ EXPECT_TRUE(accept_); EXPECT_FALSE(cancel_); EXPECT_FALSE(dont_block_); + histogram_tester_.ExpectBucketCount( + ExternalProtocolHandler::kRememberCheckboxMetric, 0 /* false */, 1); + histogram_tester_.ExpectBucketCount( + ExternalProtocolHandler::kHandleStateMetric, + ExternalProtocolHandler::LAUNCH, 1); } IN_PROC_BROWSER_TEST_F(ExternalProtocolDialogBrowserTest, @@ -127,6 +136,11 @@ EXPECT_TRUE(accept_); EXPECT_FALSE(cancel_); EXPECT_TRUE(dont_block_); + histogram_tester_.ExpectBucketCount( + ExternalProtocolHandler::kRememberCheckboxMetric, 1 /* true */, 1); + histogram_tester_.ExpectBucketCount( + ExternalProtocolHandler::kHandleStateMetric, + ExternalProtocolHandler::CHECKED_LAUNCH, 1); } IN_PROC_BROWSER_TEST_F(ExternalProtocolDialogBrowserTest, TestCancel) { @@ -136,6 +150,11 @@ EXPECT_FALSE(accept_); EXPECT_TRUE(cancel_); EXPECT_FALSE(dont_block_); + histogram_tester_.ExpectBucketCount( + ExternalProtocolHandler::kRememberCheckboxMetric, 0 /* false */, 1); + histogram_tester_.ExpectBucketCount( + ExternalProtocolHandler::kHandleStateMetric, + ExternalProtocolHandler::DONT_LAUNCH, 1); } IN_PROC_BROWSER_TEST_F(ExternalProtocolDialogBrowserTest, @@ -147,6 +166,11 @@ EXPECT_FALSE(accept_); EXPECT_TRUE(cancel_); EXPECT_TRUE(dont_block_); + histogram_tester_.ExpectBucketCount( + ExternalProtocolHandler::kRememberCheckboxMetric, 1 /* true */, 1); + histogram_tester_.ExpectBucketCount( + ExternalProtocolHandler::kHandleStateMetric, + ExternalProtocolHandler::CHECKED_DONT_LAUNCH, 1); } IN_PROC_BROWSER_TEST_F(ExternalProtocolDialogBrowserTest, TestClose) { @@ -157,6 +181,11 @@ EXPECT_FALSE(accept_); EXPECT_TRUE(cancel_); EXPECT_FALSE(dont_block_); + // No histogram data + histogram_tester_.ExpectTotalCount( + ExternalProtocolHandler::kRememberCheckboxMetric, 0); + histogram_tester_.ExpectTotalCount( + ExternalProtocolHandler::kHandleStateMetric, 0); } IN_PROC_BROWSER_TEST_F(ExternalProtocolDialogBrowserTest, @@ -169,4 +198,9 @@ EXPECT_FALSE(accept_); EXPECT_TRUE(cancel_); EXPECT_FALSE(dont_block_); + // No histogram data + histogram_tester_.ExpectTotalCount( + ExternalProtocolHandler::kRememberCheckboxMetric, 0); + histogram_tester_.ExpectTotalCount( + ExternalProtocolHandler::kHandleStateMetric, 0); }
diff --git a/chrome/browser/ui/views/find_bar_view.cc b/chrome/browser/ui/views/find_bar_view.cc index 3b58693..76e1d27 100644 --- a/chrome/browser/ui/views/find_bar_view.cc +++ b/chrome/browser/ui/views/find_bar_view.cc
@@ -30,8 +30,8 @@ #include "ui/events/event.h" #include "ui/gfx/color_palette.h" #include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/vector_icons_public.h" #include "ui/native_theme/native_theme.h" +#include "ui/vector_icons/vector_icons.h" #include "ui/views/background.h" #include "ui/views/border.h" #include "ui/views/bubble/bubble_border.h" @@ -129,7 +129,7 @@ find_previous_button_->SetIcon(kCaretUpIcon); find_next_button_->SetIcon(kCaretDownIcon); - close_button_->SetIcon(gfx::VectorIconId::BAR_CLOSE); + close_button_->SetIcon(ui::kCloseIcon); find_previous_button_->set_id(VIEW_ID_FIND_IN_PAGE_PREVIOUS_BUTTON); find_previous_button_->SetFocusForPlatform();
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc index 3da8b11..094f1d0f 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
@@ -69,6 +69,8 @@ return nullptr; } +void BrowserNonClientFrameView::UpdateClientArea() {} + void BrowserNonClientFrameView::VisibilityChanged(views::View* starting_from, bool is_visible) { // UpdateTaskbarDecoration() calls DrawTaskbarDecoration(), but that does
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h index 8009b70..7e1dca0c 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
@@ -57,6 +57,9 @@ // Returns the profile switcher button, if this frame has any. virtual views::View* GetProfileSwitcherView() const; + // Provided for mus. Updates the client-area of the WindowTreeHostMus. + virtual void UpdateClientArea(); + // Overriden from views::View. void VisibilityChanged(views::View* starting_from, bool is_visible) override;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.cc index 6ea7c1c..3fa2a16a7 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/ui/views/frame/browser_header_painter_ash.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/immersive_mode_controller.h" +#include "chrome/browser/ui/views/frame/top_container_view.h" #include "chrome/browser/ui/views/profiles/profile_indicator_icon.h" #include "chrome/browser/ui/views/tab_icon_view.h" #include "chrome/browser/ui/views/tabs/tab_strip.h" @@ -182,6 +183,52 @@ #endif } +void BrowserNonClientFrameViewMus::UpdateClientArea() { + std::vector<gfx::Rect> additional_client_area; + int top_container_offset = 0; + ImmersiveModeController* immersive_mode_controller = + browser_view()->immersive_mode_controller(); + // Frame decorations (the non-client area) are visible if not in immersive + // mode, or in immersive mode *and* the reveal widget is showing. + const bool show_frame_decorations = !immersive_mode_controller->IsEnabled() || + immersive_mode_controller->IsRevealed(); + if (browser_view()->IsTabStripVisible() && show_frame_decorations) { + gfx::Rect tab_strip_bounds(GetBoundsForTabStrip(tab_strip_)); + if (!tab_strip_bounds.IsEmpty() && tab_strip_->max_x()) { + tab_strip_bounds.set_width(tab_strip_->max_x()); + if (immersive_mode_controller->IsEnabled()) { + top_container_offset = + immersive_mode_controller->GetTopContainerVerticalOffset( + browser_view()->top_container()->size()); + tab_strip_bounds.set_y(tab_strip_bounds.y() + top_container_offset); + tab_strip_bounds.Intersect(gfx::Rect(size())); + } + additional_client_area.push_back(tab_strip_bounds); + } + } + aura::WindowTreeHostMus* window_tree_host_mus = + static_cast<aura::WindowTreeHostMus*>( + GetWidget()->GetNativeWindow()->GetHost()); + if (show_frame_decorations) { + window_tree_host_mus->SetClientArea( + views::WindowManagerFrameValues::instance().normal_insets, + additional_client_area); + views::Widget* reveal_widget = immersive_mode_controller->GetRevealWidget(); + if (reveal_widget) { + // In immersive mode the reveal widget needs the same client area as + // the Browser widget. This way mus targets the window manager (ash) for + // clicks in the frame decoration. + static_cast<aura::WindowTreeHostMus*>( + reveal_widget->GetNativeWindow()->GetHost()) + ->SetClientArea( + views::WindowManagerFrameValues::instance().normal_insets, + additional_client_area); + } + } else { + window_tree_host_mus->SetClientArea(gfx::Insets(), additional_client_area); + } +} + /////////////////////////////////////////////////////////////////////////////// // views::NonClientFrameView: @@ -336,21 +383,6 @@ /////////////////////////////////////////////////////////////////////////////// // BrowserNonClientFrameViewMus, private: -void BrowserNonClientFrameViewMus::UpdateClientArea() { - std::vector<gfx::Rect> additional_client_area; - if (tab_strip_) { - gfx::Rect tab_strip_bounds(GetBoundsForTabStrip(tab_strip_)); - if (!tab_strip_bounds.IsEmpty() && tab_strip_->max_x()) { - tab_strip_bounds.set_width(tab_strip_->max_x()); - additional_client_area.push_back(tab_strip_bounds); - } - } - static_cast<aura::WindowTreeHostMus*>( - GetWidget()->GetNativeWindow()->GetHost()) - ->SetClientArea(views::WindowManagerFrameValues::instance().normal_insets, - additional_client_area); -} - void BrowserNonClientFrameViewMus::TabStripMaxXChanged(TabStrip* tab_strip) { UpdateClientArea(); }
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.h index 4ead067..b25f59b 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.h +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.h
@@ -37,6 +37,7 @@ int GetThemeBackgroundXInset() const override; void UpdateThrobber(bool running) override; views::View* GetProfileSwitcherView() const override; + void UpdateClientArea() override; // views::NonClientFrameView: gfx::Rect GetBoundsForClientView() const override; @@ -65,9 +66,6 @@ void UpdateProfileIcons() override; private: - // Resets the client area of the WindowTreeHostMus. - void UpdateClientArea(); - // TabStripObserver: void TabStripMaxXChanged(TabStrip* tab_strip) override; void TabStripDeleted(TabStrip* tab_strip) override;
diff --git a/chrome/browser/ui/views/frame/browser_view_layout_unittest.cc b/chrome/browser/ui/views/frame/browser_view_layout_unittest.cc index 0ad5522b..ac09828 100644 --- a/chrome/browser/ui/views/frame/browser_view_layout_unittest.cc +++ b/chrome/browser/ui/views/frame/browser_view_layout_unittest.cc
@@ -112,6 +112,7 @@ } void OnFindBarVisibleBoundsChanged( const gfx::Rect& new_visible_bounds) override {} + views::Widget* GetRevealWidget() override { return nullptr; } private: DISALLOW_COPY_AND_ASSIGN(MockImmersiveModeController);
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller.h b/chrome/browser/ui/views/frame/immersive_mode_controller.h index 99fafc6..be3cbeb 100644 --- a/chrome/browser/ui/views/frame/immersive_mode_controller.h +++ b/chrome/browser/ui/views/frame/immersive_mode_controller.h
@@ -16,6 +16,10 @@ class Size; } +namespace views { +class Widget; +} + // A lock which will keep the top-of-window views revealed for its // lifetime. // See ImmersiveModeController::GetRevealedLock for details. @@ -111,6 +115,10 @@ Type type() const { return type_; } + // Returns the widget hosting the reveal, null if a widget isn't used to + // host the reveal, or not currently revealed. + virtual views::Widget* GetRevealWidget() = 0; + virtual void AddObserver(Observer* observer); virtual void RemoveObserver(Observer* observer);
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc index da477217..62e7fdd 100644 --- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc +++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
@@ -22,15 +22,22 @@ #include "content/public/browser/web_contents.h" #include "services/ui/public/cpp/property_type_converters.h" #include "services/ui/public/interfaces/window_manager.mojom.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/aura/mus/mus_types.h" #include "ui/aura/mus/mus_util.h" #include "ui/aura/mus/property_converter.h" +#include "ui/aura/mus/window_port_mus.h" #include "ui/aura/window.h" +#include "ui/compositor/layer.h" #include "ui/compositor/paint_context.h" #include "ui/compositor/paint_recorder.h" +#include "ui/views/background.h" #include "ui/views/mus/mus_client.h" #include "ui/views/view.h" +#include "ui/views/widget/native_widget_aura.h" #include "ui/views/widget/widget.h" #include "ui/views/window/non_client_view.h" +#include "ui/wm/core/window_util.h" namespace { @@ -65,24 +72,39 @@ DISALLOW_COPY_AND_ASSIGN(ImmersiveRevealedLockAsh); }; -// TODO(sky): remove this, should instead create a layer that is clone of -// existing layers. http://crbug.com/640378. -class DelegatingPaintView : public views::View { +// View responsible for mirroring the content of the TopContainer. This is done +// by way of mirroring the actual layers. +class TopContainerMirrorView : public views::View { public: - explicit DelegatingPaintView(views::View* view) : view_(view) {} - - ~DelegatingPaintView() override {} + explicit TopContainerMirrorView(views::View* view) : view_(view) { + DCHECK(view_->layer()); + SetPaintToLayer(); + layer()->SetFillsBoundsOpaquely(false); + // At this point we have no size. Wait for the first resize before we + // create the mirrored layer. + } + ~TopContainerMirrorView() override {} // views::View: - void PaintChildren(const ui::PaintContext& context) override { - view_->Paint(ui::PaintContext( - context, ui::PaintContext::CLONE_WITHOUT_INVALIDATION)); + void OnBoundsChanged(const gfx::Rect& previous_bounds) override { + if (mirrored_layer_tree_owner_ && + mirrored_layer_tree_owner_->root()->size() == size()) { + return; + } + + mirrored_layer_tree_owner_.reset(); + DCHECK(view_->layer()); // SetPaintToLayer() should have been called. + mirrored_layer_tree_owner_ = wm::MirrorLayers(view_, false); + mirrored_layer_tree_owner_->root()->SetBounds(gfx::Rect(size())); + layer()->Add(mirrored_layer_tree_owner_->root()); } private: views::View* view_; - DISALLOW_COPY_AND_ASSIGN(DelegatingPaintView); + std::unique_ptr<ui::LayerTreeOwner> mirrored_layer_tree_owner_; + + DISALLOW_COPY_AND_ASSIGN(TopContainerMirrorView); }; } // namespace @@ -162,6 +184,10 @@ find_bar_visible_bounds_in_screen_ = new_visible_bounds_in_screen; } +views::Widget* ImmersiveModeControllerAsh::GetRevealWidget() { + return mash_reveal_widget_.get(); +} + void ImmersiveModeControllerAsh::EnableWindowObservers(bool enable) { if (observers_enabled_ == enable) return; @@ -172,6 +198,8 @@ ->fullscreen_controller()); if (enable) { if (chrome::IsRunningInMash()) { + browser_view_->GetWidget()->GetNativeView()->GetRootWindow()->AddObserver( + this); // TODO: http://crbug.com/640381. NOTIMPLEMENTED(); } else { @@ -180,6 +208,10 @@ registrar_.Add(this, chrome::NOTIFICATION_FULLSCREEN_CHANGED, source); } else { if (chrome::IsRunningInMash()) { + browser_view_->GetWidget() + ->GetNativeView() + ->GetRootWindow() + ->RemoveObserver(this); // TODO: http://crbug.com/640381. NOTIMPLEMENTED(); } else { @@ -235,11 +267,18 @@ [ui::mojom::WindowManager::kRenderParentTitleArea_Property] = mojo::ConvertTo<std::vector<uint8_t>>( static_cast<aura::PropertyConverter::PrimitiveType>(true)); + init_params.mus_properties + [ui::mojom::WindowManager::kWindowIgnoredByShelf_Property] = + mojo::ConvertTo<std::vector<uint8_t>>(true); init_params.name = "ChromeImmersiveRevealWindow"; + // We want events to fall through to the real views. init_params.accept_events = false; init_params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; init_params.activatable = views::Widget::InitParams::ACTIVATABLE_NO; - init_params.parent = native_window_; + init_params.parent = native_window_->GetRootWindow(); + // The widget needs to be translucent so the frame decorations drawn by the + // window manager are visible. + init_params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; const gfx::Rect& top_container_bounds = browser_view_->top_container()->bounds(); init_params.bounds = @@ -247,7 +286,11 @@ top_container_bounds.height()); mash_reveal_widget_->Init(init_params); mash_reveal_widget_->SetContentsView( - new DelegatingPaintView(browser_view_->top_container())); + new TopContainerMirrorView(browser_view_->top_container())); + // Disable the default animation as we want to the window to slide in nicely, + // not slide and inherit the default window animations. + mash_reveal_widget_->GetNativeWindow()->SetProperty( + aura::client::kAnimationsDisabledKey, true); mash_reveal_widget_->StackAtTop(); mash_reveal_widget_->Show(); } @@ -261,6 +304,11 @@ visible_fraction_ = 0; browser_view_->top_container()->SetPaintToLayer(); + // In mash the window manager (ash) also renders to the non-client area. In + // order to see the decorations drawn by ash the layer needs to be marked as + // not filling bounds opaquely. + if (chrome::IsRunningInMash()) + browser_view_->top_container()->layer()->SetFillsBoundsOpaquely(false); UpdateTabIndicators(); LayoutBrowserRootView(); CreateMashRevealWidget(); @@ -286,15 +334,17 @@ } void ImmersiveModeControllerAsh::SetVisibleFraction(double visible_fraction) { - if (visible_fraction_ != visible_fraction) { - visible_fraction_ = visible_fraction; - browser_view_->Layout(); + if (visible_fraction_ == visible_fraction) + return; - if (mash_reveal_widget_) { - gfx::Rect bounds = mash_reveal_widget_->GetNativeWindow()->bounds(); - bounds.set_y(visible_fraction * bounds.height() - bounds.height()); - mash_reveal_widget_->SetBounds(bounds); - } + visible_fraction_ = visible_fraction; + browser_view_->Layout(); + browser_view_->frame()->GetFrameView()->UpdateClientArea(); + + if (mash_reveal_widget_) { + gfx::Rect bounds = mash_reveal_widget_->GetNativeWindow()->bounds(); + bounds.set_y(visible_fraction * bounds.height() - bounds.height()); + mash_reveal_widget_->SetBounds(bounds); } } @@ -359,3 +409,15 @@ if (tab_indicator_visibility_changed) LayoutBrowserRootView(); } + +void ImmersiveModeControllerAsh::OnWindowPropertyChanged(aura::Window* window, + const void* key, + intptr_t old) { + // In mash the window manager may move us out of immersive mode by changing + // the show state. When this happens notify the controller. + DCHECK(chrome::IsRunningInMash()); + if (key == aura::client::kShowStateKey && + !browser_view_->GetWidget()->IsFullscreen()) { + SetEnabled(false); + } +}
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h index 4427bff06..7d887fe5 100644 --- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h +++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h
@@ -14,6 +14,7 @@ #include "chrome/browser/ui/views/frame/immersive_mode_controller.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" +#include "ui/aura/window_observer.h" #include "ui/gfx/geometry/rect.h" namespace aura { @@ -26,7 +27,8 @@ : public ImmersiveModeController, public ash::ImmersiveFullscreenControllerDelegate, public ash::wm::WindowStateObserver, - public content::NotificationObserver { + public content::NotificationObserver, + public aura::WindowObserver { public: ImmersiveModeControllerAsh(); ~ImmersiveModeControllerAsh() override; @@ -46,6 +48,7 @@ WARN_UNUSED_RESULT; void OnFindBarVisibleBoundsChanged( const gfx::Rect& new_visible_bounds_in_screen) override; + views::Widget* GetRevealWidget() override; private: // Enables or disables observers for window restore and entering / exiting @@ -82,6 +85,11 @@ const content::NotificationSource& source, const content::NotificationDetails& details) override; + // aura::WindowObserver override: + void OnWindowPropertyChanged(aura::Window* window, + const void* key, + intptr_t old) override; + std::unique_ptr<ash::ImmersiveFullscreenController> controller_; // Not owned.
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_stub.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_stub.cc index b25f8007..fd01582 100644 --- a/chrome/browser/ui/views/frame/immersive_mode_controller_stub.cc +++ b/chrome/browser/ui/views/frame/immersive_mode_controller_stub.cc
@@ -48,3 +48,7 @@ void ImmersiveModeControllerStub::OnFindBarVisibleBoundsChanged( const gfx::Rect& new_visible_bounds_in_screen) { } + +views::Widget* ImmersiveModeControllerStub::GetRevealWidget() { + return nullptr; +}
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_stub.h b/chrome/browser/ui/views/frame/immersive_mode_controller_stub.h index 1f69537..fb33aea 100644 --- a/chrome/browser/ui/views/frame/immersive_mode_controller_stub.h +++ b/chrome/browser/ui/views/frame/immersive_mode_controller_stub.h
@@ -30,6 +30,7 @@ WARN_UNUSED_RESULT; void OnFindBarVisibleBoundsChanged( const gfx::Rect& new_visible_bounds_in_screen) override; + views::Widget* GetRevealWidget() override; private: DISALLOW_COPY_AND_ASSIGN(ImmersiveModeControllerStub);
diff --git a/chrome/browser/ui/views/harmony/harmony_layout_delegate.cc b/chrome/browser/ui/views/harmony/harmony_layout_delegate.cc index c833ef37..eb174431 100644 --- a/chrome/browser/ui/views/harmony/harmony_layout_delegate.cc +++ b/chrome/browser/ui/views/harmony/harmony_layout_delegate.cc
@@ -19,6 +19,12 @@ switch (metric) { case Metric::DIALOG_BUTTON_MARGIN: return kHarmonyLayoutUnit; + case Metric::DIALOG_BUTTON_TOP_SPACING: + return kHarmonyLayoutUnit; + case Metric::DIALOG_CLOSE_BUTTON_MARGIN: + // TODO(pkasting): The "- 4" here is a hack that matches the extra padding + // in vector_icon_button.cc and should be removed when that padding is. + return (kHarmonyLayoutUnit / 2) - 4; case Metric::PANEL_CONTENT_MARGIN: return kHarmonyLayoutUnit; case Metric::RELATED_BUTTON_HORIZONTAL_SPACING:
diff --git a/chrome/browser/ui/views/harmony/layout_delegate.cc b/chrome/browser/ui/views/harmony/layout_delegate.cc index c5a7425d..5ff7798 100644 --- a/chrome/browser/ui/views/harmony/layout_delegate.cc +++ b/chrome/browser/ui/views/harmony/layout_delegate.cc
@@ -24,6 +24,10 @@ switch (metric) { case Metric::DIALOG_BUTTON_MARGIN: return views::kButtonHEdgeMarginNew; + case Metric::DIALOG_BUTTON_TOP_SPACING: + return 0; + case Metric::DIALOG_CLOSE_BUTTON_MARGIN: + return views::kCloseButtonMargin; case Metric::PANEL_CONTENT_MARGIN: return views::kPanelHorizMargin; case Metric::RELATED_BUTTON_HORIZONTAL_SPACING:
diff --git a/chrome/browser/ui/views/harmony/layout_delegate.h b/chrome/browser/ui/views/harmony/layout_delegate.h index cd3c11e..6213d1c9 100644 --- a/chrome/browser/ui/views/harmony/layout_delegate.h +++ b/chrome/browser/ui/views/harmony/layout_delegate.h
@@ -10,9 +10,16 @@ class LayoutDelegate { public: enum class Metric { - // Horizontal or vertical margin between the edge of a dialog and a + // Margin between the edge of a dialog and the left, right, or bottom of a // contained button. DIALOG_BUTTON_MARGIN, + // In theory, this is the spacing between a dialog button and the content + // above it. In practice, what the code does with this value, at least + // pre-Harmony, defies easy explanation. + DIALOG_BUTTON_TOP_SPACING, + // Horizontal or vertical margin between the edge of a dialog and the close + // button in the upper trailing corner. + DIALOG_CLOSE_BUTTON_MARGIN, // Horizontal or vertical margin between the edge of a panel and the // contained content. PANEL_CONTENT_MARGIN,
diff --git a/chrome/browser/ui/views/infobars/infobar_view.cc b/chrome/browser/ui/views/infobars/infobar_view.cc index fd33301..ad1f707 100644 --- a/chrome/browser/ui/views/infobars/infobar_view.cc +++ b/chrome/browser/ui/views/infobars/infobar_view.cc
@@ -23,9 +23,9 @@ #include "ui/gfx/color_palette.h" #include "ui/gfx/image/image.h" #include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/vector_icons_public.h" #include "ui/native_theme/common_theme.h" #include "ui/native_theme/native_theme.h" +#include "ui/vector_icons/vector_icons.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/controls/button/label_button_border.h" #include "ui/views/controls/button/md_text_button.h" @@ -166,7 +166,7 @@ } close_button_ = new views::VectorIconButton(this); - close_button_->SetIcon(gfx::VectorIconId::BAR_CLOSE); + close_button_->SetIcon(ui::kCloseIcon); close_button_->SetAccessibleName( l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE)); close_button_->SetFocusForPlatform();
diff --git a/chrome/browser/ui/webui/OWNERS b/chrome/browser/ui/webui/OWNERS index 838ff91..df3d93f 100644 --- a/chrome/browser/ui/webui/OWNERS +++ b/chrome/browser/ui/webui/OWNERS
@@ -27,6 +27,8 @@ per-file signin_internals_ui*=achuith@chromium.org per-file snippets_internals*=file://components/ntp_snippets/OWNERS +per-file ntp_tiles_internals_ui.*=file://components/ntp_tiles/OWNERS +per-file popular_sites_internals_ui.*=file://components/ntp_tiles/OWNERS # Maintaining ownership from this file's original Chrome OS location. per-file device_log_ui*=stevenjb@chromium.org
diff --git a/chrome/browser/ui/webui/about_ui.cc b/chrome/browser/ui/webui/about_ui.cc index 657bd72..e2389f1 100644 --- a/chrome/browser/ui/webui/about_ui.cc +++ b/chrome/browser/ui/webui/about_ui.cc
@@ -30,6 +30,7 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "base/task_scheduler/post_task.h" #include "base/threading/thread.h" #include "base/values.h" #include "build/build_config.h" @@ -322,15 +323,14 @@ return; } // Load local Chrome OS credits from the disk. - BrowserThread::PostBlockingPoolTaskAndReply( - FROM_HERE, - base::Bind(&ChromeOSCreditsHandler::LoadCreditsFileOnBlockingPool, - this), + base::PostTaskWithTraitsAndReply( + FROM_HERE, base::TaskTraits().MayBlock().WithPriority( + base::TaskPriority::BACKGROUND), + base::Bind(&ChromeOSCreditsHandler::LoadCreditsFileAsync, this), base::Bind(&ChromeOSCreditsHandler::ResponseOnUIThread, this)); } - void LoadCreditsFileOnBlockingPool() { - DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); + void LoadCreditsFileAsync() { base::FilePath credits_file_path(chrome::kChromeOSCreditsPath); if (!base::ReadFileToString(credits_file_path, &contents_)) { // File with credits not found, ResponseOnUIThread will load credits
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc index a0c0c2580..a5a7b81f 100644 --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -115,6 +115,7 @@ #include "chrome/browser/ui/webui/offline/offline_internals_ui.h" #include "chrome/browser/ui/webui/popular_sites_internals_ui.h" #include "chrome/browser/ui/webui/snippets_internals_ui.h" +#include "chrome/browser/ui/webui/webapks_ui.h" #if defined(ENABLE_VR_SHELL) || defined(ENABLE_WEBVR) #include "chrome/browser/ui/webui/vr_shell/vr_shell_ui_ui.h" #endif @@ -519,6 +520,8 @@ if (url.host_piece() == chrome::kChromeUISnippetsInternalsHost && !profile->IsOffTheRecord()) return &NewWebUI<SnippetsInternalsUI>; + if (url.host_piece() == chrome::kChromeUIWebApksHost) + return &NewWebUI<WebApksUI>; #if defined(ENABLE_VR_SHELL) || defined(ENABLE_WEBVR) if (url.host_piece() == chrome::kChromeUIVrShellUIHost) return &NewWebUI<VrShellUIUI>;
diff --git a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc index 34363d31..7e0c9a7 100644 --- a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
@@ -156,14 +156,16 @@ // user accepts ToS then prefs::kArcEnabled is left activated. If user skips // ToS then prefs::kArcEnabled is automatically reset in ArcSessionManager. profile->GetPrefs()->SetBoolean(prefs::kArcEnabled, true); + + system::TimezoneSettings::GetInstance()->AddObserver(this); + + ShowScreen(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE); + + UpdateTimeZone(); pref_handler_.reset(new arc::ArcOptInPreferenceHandler( this, profile->GetPrefs())); pref_handler_->Start(); - UpdateTimeZone(); - system::TimezoneSettings::GetInstance()->AddObserver(this); - - ShowScreen(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE); } void ArcTermsOfServiceScreenHandler::HandleSkip() {
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 925b0ba..e0a08b80 100644 --- a/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.cc
@@ -121,6 +121,7 @@ builder->Add("eulaScreenAccessibleTitle", IDS_EULA_SCREEN_ACCESSIBLE_TITLE); builder->Add("checkboxLogging", IDS_EULA_CHECKBOX_ENABLE_LOGGING); builder->Add("back", IDS_EULA_BACK_BUTTON); + builder->Add("next", IDS_EULA_NEXT_BUTTON); builder->Add("acceptAgreement", IDS_EULA_ACCEPT_AND_CONTINUE_BUTTON); builder->Add("eulaSystemInstallationSettings", IDS_EULA_SYSTEM_SECURITY_SETTING);
diff --git a/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc b/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc index 2dd101c..3b3c24e 100644 --- a/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc +++ b/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc
@@ -10,6 +10,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chromeos/login/screens/network_error.h" +#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chromeos/network/network_state.h" #include "chromeos/network/network_state_handler.h" #include "chromeos/network/proxy/proxy_config_handler.h" @@ -82,6 +83,17 @@ if (network->is_captive_portal()) return NetworkStateInformer::CAPTIVE_PORTAL; } + + // If there is no connection to the internet report it as online for the + // Active Directory devices. These devices does not have to be online to reach + // the server. + // TODO(rsorokin): Fix reporting network connectivity for Active Directory + // devices. (see crbug.com/685691) + policy::BrowserPolicyConnectorChromeOS* connector = + g_browser_process->platform_part()->browser_policy_connector_chromeos(); + if (connector->IsActiveDirectoryManaged()) + return NetworkStateInformer::ONLINE; + return NetworkStateInformer::OFFLINE; }
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc index 7c63c94..c90b6a3 100644 --- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc +++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -116,6 +116,7 @@ const char kEnrollmentJSPath[] = "enrollment.js"; const char kArcPlaystoreCSSPath[] = "playstore.css"; const char kArcPlaystoreJSPath[] = "playstore.js"; +const char kArcPlaystoreLogoPath[] = "playstore.svg"; // Creates a WebUIDataSource for chrome://oobe content::WebUIDataSource* CreateOobeUIDataSource( @@ -158,6 +159,8 @@ // Required for postprocessing of Goolge PlayStore Terms. source->AddResourcePath(kArcPlaystoreCSSPath, IDR_ARC_SUPPORT_PLAYSTORE_CSS); source->AddResourcePath(kArcPlaystoreJSPath, IDR_ARC_SUPPORT_PLAYSTORE_JS); + source->AddResourcePath(kArcPlaystoreLogoPath, + IDR_ARC_SUPPORT_PLAYSTORE_LOGO); source->AddResourcePath(kKeyboardUtilsJSPath, IDR_KEYBOARD_UTILS_JS); source->OverrideContentSecurityPolicyChildSrc(
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc index 6fc2616..44fd987b 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -231,6 +231,39 @@ return true; } +void EnforcePolicyInputMethods(std::string user_input_method) { + chromeos::CrosSettings* cros_settings = chromeos::CrosSettings::Get(); + const base::ListValue* login_screen_input_methods = nullptr; + if (!cros_settings->GetList(chromeos::kDeviceLoginScreenInputMethods, + &login_screen_input_methods)) { + return; + } + + std::vector<std::string> allowed_input_methods; + + // Add user's input method first so it is pre-selected. + if (!user_input_method.empty()) { + allowed_input_methods.push_back(user_input_method); + } + + std::string input_method; + for (const auto& input_method_entry : *login_screen_input_methods) { + if (input_method_entry->GetAsString(&input_method)) + allowed_input_methods.push_back(input_method); + } + chromeos::input_method::InputMethodManager* imm = + chromeos::input_method::InputMethodManager::Get(); + imm->GetActiveIMEState()->SetAllowedInputMethods(allowed_input_methods); +} + +void StopEnforcingPolicyInputMethods() { + // Empty means all input methods are allowed + std::vector<std::string> allowed_input_methods; + chromeos::input_method::InputMethodManager* imm = + chromeos::input_method::InputMethodManager::Get(); + imm->GetActiveIMEState()->SetAllowedInputMethods(allowed_input_methods); +} + } // namespace // LoginScreenContext implementation ------------------------------------------ @@ -294,6 +327,12 @@ chromeos::input_method::InputMethodManager::Get()->GetImeKeyboard(); if (keyboard) keyboard->AddObserver(this); + OnAllowedInputMethodsChanged(); + allowed_input_methods_subscription_ = + chromeos::CrosSettings::Get()->AddSettingsObserver( + chromeos::kDeviceLoginScreenInputMethods, + base::Bind(&SigninScreenHandler::OnAllowedInputMethodsChanged, + base::Unretained(this))); content::ServiceManagerConnection::GetForProcess() ->GetConnector() @@ -312,6 +351,7 @@ chromeos::input_method::InputMethodManager::Get()->GetImeKeyboard(); if (keyboard) keyboard->RemoveObserver(this); + StopEnforcingPolicyInputMethods(); weak_factory_.InvalidateWeakPtrs(); if (delegate_) delegate_->SetWebUIHandler(nullptr); @@ -354,6 +394,8 @@ const std::string input_method = GetUserLRUInputMethod(username); + EnforcePolicyInputMethods(input_method); + if (!input_method.empty()) succeed = SetUserInputMethodImpl(username, input_method, ime_state); @@ -568,6 +610,7 @@ AddCallback("showLoadingTimeoutError", &SigninScreenHandler::HandleShowLoadingTimeoutError); AddCallback("focusPod", &SigninScreenHandler::HandleFocusPod); + AddCallback("noPodFocused", &SigninScreenHandler::HandleNoPodFocused); AddCallback("getPublicSessionKeyboardLayouts", &SigninScreenHandler::HandleGetPublicSessionKeyboardLayouts); AddCallback("getTouchViewState", @@ -1387,6 +1430,8 @@ if (!test_focus_pod_callback_.is_null()) test_focus_pod_callback_.Run(); + focused_pod_account_id_ = base::MakeUnique<AccountId>(account_id); + const user_manager::User* user = user_manager::UserManager::Get()->FindUser(account_id); // |user| may be nullptr in kiosk mode or unit tests. @@ -1408,6 +1453,11 @@ } } +void SigninScreenHandler::HandleNoPodFocused() { + focused_pod_account_id_.reset(); + EnforcePolicyInputMethods(std::string()); +} + void SigninScreenHandler::HandleGetPublicSessionKeyboardLayouts( const AccountId& account_id, const std::string& locale) { @@ -1555,4 +1605,14 @@ HandleResyncUserData(); } +void SigninScreenHandler::OnAllowedInputMethodsChanged() { + if (focused_pod_account_id_) { + std::string user_input_method = + GetUserLRUInputMethod(focused_pod_account_id_->GetUserEmail()); + EnforcePolicyInputMethods(user_input_method); + } else { + EnforcePolicyInputMethods(std::string()); + } +} + } // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h index 60809af..63978af 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
@@ -376,6 +376,7 @@ void HandleShowLoadingTimeoutError(); void HandleShowSupervisedUserCreationScreen(); void HandleFocusPod(const AccountId& account_id); + void HandleNoPodFocused(); void HandleHardlockPod(const std::string& user_id); void HandleLaunchKioskApp(const AccountId& app_account_id, bool diagnostic_mode); @@ -431,6 +432,9 @@ // Callback invoked after the feedback is finished. void OnFeedbackFinished(); + // Called when the cros property controlling allowed input methods changes. + void OnAllowedInputMethodsChanged(); + // Current UI state of the signin screen. UIState ui_state_ = UI_STATE_UNKNOWN; @@ -467,6 +471,9 @@ content::NotificationRegistrar registrar_; + std::unique_ptr<CrosSettings::ObserverSubscription> + allowed_input_methods_subscription_; + // Whether there is an auth UI pending. This flag is set on receiving // NOTIFICATION_AUTH_NEEDED and reset on either NOTIFICATION_AUTH_SUPPLIED or // NOTIFICATION_AUTH_CANCELLED. @@ -511,6 +518,8 @@ std::unique_ptr<LoginFeedback> login_feedback_; + std::unique_ptr<AccountId> focused_pod_account_id_; + base::WeakPtrFactory<SigninScreenHandler> weak_factory_; DISALLOW_COPY_AND_ASSIGN(SigninScreenHandler);
diff --git a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc index e3d767e2..955022e4 100644 --- a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc
@@ -8,7 +8,7 @@ #include "base/values.h" #include "chrome/browser/chromeos/login/oobe_screen.h" -#include "chrome/browser/chromeos/login/screens/update_model.h" +#include "chrome/browser/chromeos/login/screens/update_screen.h" #include "chrome/grit/chromium_strings.h" #include "chrome/grit/generated_resources.h" #include "components/login/localized_values_builder.h" @@ -21,13 +21,11 @@ namespace chromeos { -UpdateScreenHandler::UpdateScreenHandler() - : BaseScreenHandler(kJsScreenPath), model_(nullptr), show_on_init_(false) { -} +UpdateScreenHandler::UpdateScreenHandler() : BaseScreenHandler(kJsScreenPath) {} UpdateScreenHandler::~UpdateScreenHandler() { - if (model_) - model_->OnViewDestroyed(this); + if (screen_) + screen_->OnViewDestroyed(this); } void UpdateScreenHandler::DeclareLocalizedValues( @@ -76,13 +74,13 @@ void UpdateScreenHandler::Hide() { } -void UpdateScreenHandler::Bind(UpdateModel& model) { - model_ = &model; - BaseScreenHandler::SetBaseScreen(model_); +void UpdateScreenHandler::Bind(UpdateScreen* screen) { + screen_ = screen; + BaseScreenHandler::SetBaseScreen(screen_); } void UpdateScreenHandler::Unbind() { - model_ = nullptr; + screen_ = nullptr; BaseScreenHandler::SetBaseScreen(nullptr); }
diff --git a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h index c979a06..a948207 100644 --- a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h
@@ -19,10 +19,11 @@ UpdateScreenHandler(); ~UpdateScreenHandler() override; + private: // UpdateView: void Show() override; void Hide() override; - void Bind(UpdateModel& model) override; + void Bind(UpdateScreen* screen) override; void Unbind() override; // BaseScreenHandler: @@ -30,11 +31,10 @@ ::login::LocalizedValuesBuilder* builder) override; void Initialize() override; - private: - UpdateModel* model_; + UpdateScreen* screen_ = nullptr; - // Keeps whether screen should be shown right after initialization. - bool show_on_init_; + // If true, Initialize() will call Show(). + bool show_on_init_ = false; DISALLOW_COPY_AND_ASSIGN(UpdateScreenHandler); };
diff --git a/chrome/browser/ui/webui/chromeos/login/user_board_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/user_board_screen_handler.cc index 28869932..aa9ce9be 100644 --- a/chrome/browser/ui/webui/chromeos/login/user_board_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/user_board_screen_handler.cc
@@ -4,13 +4,12 @@ #include "chrome/browser/ui/webui/chromeos/login/user_board_screen_handler.h" -#include "chrome/browser/chromeos/login/ui/models/user_board_model.h" +#include "chrome/browser/chromeos/login/screens/user_selection_screen.h" #include "components/login/localized_values_builder.h" namespace chromeos { -UserBoardScreenHandler::UserBoardScreenHandler() - : model_(nullptr), weak_factory_(this) {} +UserBoardScreenHandler::UserBoardScreenHandler() : weak_factory_(this) {} UserBoardScreenHandler::~UserBoardScreenHandler() { } @@ -33,24 +32,24 @@ //----------------- Handlers void UserBoardScreenHandler::HandleGetUsers() { - CHECK(model_); - model_->SendUserList(); + CHECK(screen_); + screen_->SendUserList(); } void UserBoardScreenHandler::HandleHardlockPod(const AccountId& account_id) { - CHECK(model_); - model_->HardLockPod(account_id); + CHECK(screen_); + screen_->HardLockPod(account_id); } void UserBoardScreenHandler::HandleAttemptUnlock(const AccountId& account_id) { - CHECK(model_); - model_->AttemptEasyUnlock(account_id); + CHECK(screen_); + screen_->AttemptEasyUnlock(account_id); } void UserBoardScreenHandler::HandleRecordClickOnLockIcon( const AccountId& account_id) { - CHECK(model_); - model_->RecordClickOnLockIcon(account_id); + CHECK(screen_); + screen_->RecordClickOnLockIcon(account_id); } //----------------- API @@ -94,13 +93,13 @@ static_cast<int>(auth_type), base::StringValue(initial_value)); } -void UserBoardScreenHandler::Bind(UserBoardModel& model) { - model_ = &model; - BaseScreenHandler::SetBaseScreen(model_); +void UserBoardScreenHandler::Bind(UserSelectionScreen* screen) { + screen_ = screen; + BaseScreenHandler::SetBaseScreen(screen_); } void UserBoardScreenHandler::Unbind() { - model_ = nullptr; + screen_ = nullptr; BaseScreenHandler::SetBaseScreen(nullptr); }
diff --git a/chrome/browser/ui/webui/chromeos/login/user_board_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/user_board_screen_handler.h index 74b7ca0..1b25debd 100644 --- a/chrome/browser/ui/webui/chromeos/login/user_board_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/user_board_screen_handler.h
@@ -15,6 +15,9 @@ namespace chromeos { +// TODO(jdufault): Rename to UserSelectionScreenHandler and ensure this in the +// right directory. See crbug.com/672142. + // A class that handles WebUI hooks in Gaia screen. class UserBoardScreenHandler : public BaseScreenHandler, public UserBoardView { public: @@ -51,12 +54,11 @@ const AccountId& account_id, proximity_auth::ScreenlockBridge::LockHandler::AuthType auth_type, const base::string16& initial_value) override; - - void Bind(UserBoardModel& model) override; + void Bind(UserSelectionScreen* screen) override; void Unbind() override; base::WeakPtr<UserBoardView> GetWeakPtr() override; - UserBoardModel* model_; + UserSelectionScreen* screen_ = nullptr; base::WeakPtrFactory<UserBoardScreenHandler> weak_factory_; DISALLOW_COPY_AND_ASSIGN(UserBoardScreenHandler);
diff --git a/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl_unittest.cc b/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl_unittest.cc index 4ed40ad..0414c9c 100644 --- a/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl_unittest.cc +++ b/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl_unittest.cc
@@ -258,7 +258,7 @@ new CreatePresentationConnectionRequest( RenderFrameHostId(1, 2), {GURL("http://test.com"), GURL("http://test2.com")}, - GURL("http://example.com"), + url::Origin(GURL("http://example.com")), base::Bind(&MediaRouterDialogControllerImplTest:: PresentationSuccessCallback, base::Unretained(this)),
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui.cc b/chrome/browser/ui/webui/media_router/media_router_ui.cc index 1c99d01..8e8e9740 100644 --- a/chrome/browser/ui/webui/media_router/media_router_ui.cc +++ b/chrome/browser/ui/webui/media_router/media_router_ui.cc
@@ -277,7 +277,7 @@ query_result_manager_->AddObserver(this); // Use a placeholder URL as origin for mirroring. - GURL origin(chrome::kChromeUIMediaRouterURL); + url::Origin origin{GURL(chrome::kChromeUIMediaRouterURL)}; // Desktop mirror mode is always available. query_result_manager_->SetSourcesForCastMode( @@ -318,8 +318,7 @@ std::vector<MediaSource> sources = presentation_request.GetMediaSources(); presentation_request_.reset(new PresentationRequest(presentation_request)); query_result_manager_->SetSourcesForCastMode( - MediaCastMode::DEFAULT, sources, - presentation_request_->frame_url().GetOrigin()); + MediaCastMode::DEFAULT, sources, presentation_request_->frame_origin()); // Register for MediaRoute updates. NOTE(mfoltz): If there are multiple // sources that can be connected to via the dialog, this will break. We will // need to observe multiple sources (keyed by sinks) in that case. As this is @@ -391,7 +390,7 @@ bool MediaRouterUI::CreateRoute(const MediaSink::Id& sink_id, MediaCastMode cast_mode) { MediaSource::Id source_id; - GURL origin; + url::Origin origin; std::vector<MediaRouteResponseCallback> route_response_callbacks; base::TimeDelta timeout; bool incognito; @@ -409,7 +408,7 @@ const MediaSink::Id& sink_id, MediaCastMode cast_mode, MediaSource::Id* source_id, - GURL* origin, + url::Origin* origin, std::vector<MediaRouteResponseCallback>* route_response_callbacks, base::TimeDelta* timeout, bool* incognito) { @@ -439,8 +438,9 @@ } current_route_request_id_ = ++route_request_counter_; - *origin = for_default_source ? presentation_request_->frame_url().GetOrigin() - : GURL(chrome::kChromeUIMediaRouterURL); + *origin = for_default_source + ? presentation_request_->frame_origin() + : url::Origin(GURL(chrome::kChromeUIMediaRouterURL)); DVLOG(1) << "DoCreateRoute: origin: " << *origin; // There are 3 cases. In cases (1) and (3) the MediaRouterUI will need to be @@ -486,7 +486,7 @@ bool MediaRouterUI::ConnectRoute(const MediaSink::Id& sink_id, const MediaRoute::Id& route_id) { MediaSource::Id source_id; - GURL origin; + url::Origin origin; std::vector<MediaRouteResponseCallback> route_response_callbacks; base::TimeDelta timeout; bool incognito; @@ -652,7 +652,7 @@ handler_->ReturnSearchResult(found_sink_id); MediaSource::Id source_id; - GURL origin; + url::Origin origin; std::vector<MediaRouteResponseCallback> route_response_callbacks; base::TimeDelta timeout; bool incognito; @@ -707,7 +707,8 @@ } GURL MediaRouterUI::GetFrameURL() const { - return presentation_request_ ? presentation_request_->frame_url() : GURL(); + return presentation_request_ ? presentation_request_->frame_origin().GetURL() + : GURL(); } std::string MediaRouterUI::GetPresentationRequestSourceName() const {
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui.h b/chrome/browser/ui/webui/media_router/media_router_ui.h index 6e4f2b0..c2d1dca 100644 --- a/chrome/browser/ui/webui/media_router/media_router_ui.h +++ b/chrome/browser/ui/webui/media_router/media_router_ui.h
@@ -270,7 +270,7 @@ const MediaSink::Id& sink_id, MediaCastMode cast_mode, MediaSource::Id* source_id, - GURL* origin, + url::Origin* origin, std::vector<MediaRouteResponseCallback>* route_response_callbacks, base::TimeDelta* timeout, bool* incognito);
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui_unittest.cc b/chrome/browser/ui/webui/media_router/media_router_ui_unittest.cc index b2cc643..c62cad7 100644 --- a/chrome/browser/ui/webui/media_router/media_router_ui_unittest.cc +++ b/chrome/browser/ui/webui/media_router/media_router_ui_unittest.cc
@@ -114,7 +114,7 @@ MediaSink CreateSinkCompatibleWithAllSources() { MediaSink sink("sinkId", "sinkName", MediaSink::GENERIC); for (auto* observer : media_sinks_observers_) - observer->OnSinksUpdated({sink}, std::vector<GURL>()); + observer->OnSinksUpdated({sink}, std::vector<url::Origin>()); return sink; } @@ -170,7 +170,7 @@ CreateMediaRouterUI(profile()); PresentationRequest presentation_request( RenderFrameHostId(0, 0), {GURL("https://presentationurl.com")}, - GURL("https://frameurl.fakeurl")); + url::Origin(GURL("https://frameurl.fakeurl"))); media_router_ui_->OnDefaultPresentationChanged(presentation_request); std::vector<MediaRouteResponseCallback> callbacks; EXPECT_CALL( @@ -208,9 +208,9 @@ TEST_F(MediaRouterUITest, RouteRequestFromIncognito) { CreateMediaRouterUI(profile()->GetOffTheRecordProfile()); - PresentationRequest presentation_request(RenderFrameHostId(0, 0), - {GURL("https://foo.url.com/")}, - GURL("https://frameUrl")); + PresentationRequest presentation_request( + RenderFrameHostId(0, 0), {GURL("https://foo.url.com/")}, + url::Origin(GURL("https://frameUrl"))); media_router_ui_->OnDefaultPresentationChanged(presentation_request); EXPECT_CALL( @@ -477,7 +477,7 @@ create_session_request_.reset(new CreatePresentationConnectionRequest( RenderFrameHostId(0, 0), {GURL("http://google.com/presentation"), GURL("http://google.com/presentation2")}, - GURL("http://google.com"), + url::Origin(GURL("http://google.com")), base::Bind(&PresentationRequestCallbacks::Success, base::Unretained(&request_callbacks)), base::Bind(&PresentationRequestCallbacks::Error, @@ -495,7 +495,8 @@ PresentationRequestCallbacks request_callbacks(expected_error); GURL presentation_url("http://google.com/presentation"); create_session_request_.reset(new CreatePresentationConnectionRequest( - RenderFrameHostId(0, 0), {presentation_url}, GURL("http://google.com"), + RenderFrameHostId(0, 0), {presentation_url}, + url::Origin(GURL("http://google.com")), base::Bind(&PresentationRequestCallbacks::Success, base::Unretained(&request_callbacks)), base::Bind(&PresentationRequestCallbacks::Error, @@ -506,7 +507,7 @@ // presentation url to cause a NotFoundError. std::vector<MediaSink> sinks; sinks.emplace_back("sink id", "sink name", MediaSink::GENERIC); - std::vector<GURL> origins; + std::vector<url::Origin> origins; for (auto* observer : media_sinks_observers_) { if (observer->source().id() != presentation_url.spec()) { observer->OnSinksUpdated(sinks, origins); @@ -525,7 +526,8 @@ PresentationRequestCallbacks request_callbacks(expected_error); GURL presentation_url("http://google.com/presentation"); create_session_request_.reset(new CreatePresentationConnectionRequest( - RenderFrameHostId(0, 0), {presentation_url}, GURL("http://google.com"), + RenderFrameHostId(0, 0), {presentation_url}, + url::Origin(GURL("http://google.com")), base::Bind(&PresentationRequestCallbacks::Success, base::Unretained(&request_callbacks)), base::Bind(&PresentationRequestCallbacks::Error, @@ -536,7 +538,7 @@ // a NotFoundError. std::vector<MediaSink> sinks; sinks.emplace_back("sink id", "sink name", MediaSink::GENERIC); - std::vector<GURL> origins; + std::vector<url::Origin> origins; MediaSource::Id presentation_source_id = MediaSourceForPresentationUrl(presentation_url).id(); for (auto* observer : media_sinks_observers_) {
diff --git a/chrome/browser/ui/webui/media_router/query_result_manager.cc b/chrome/browser/ui/webui/media_router/query_result_manager.cc index 79fbb604..2bd508a 100644 --- a/chrome/browser/ui/webui/media_router/query_result_manager.cc +++ b/chrome/browser/ui/webui/media_router/query_result_manager.cc
@@ -12,7 +12,7 @@ #include "chrome/browser/media/router/media_router.h" #include "chrome/browser/media/router/media_sinks_observer.h" #include "content/public/browser/browser_thread.h" -#include "url/gurl.h" +#include "url/origin.h" namespace media_router { @@ -23,7 +23,7 @@ public: MediaSourceMediaSinksObserver(MediaCastMode cast_mode, const MediaSource& source, - const GURL& origin, + const url::Origin& origin, MediaRouter* router, QueryResultManager* result_manager) : MediaSinksObserver(router, source, origin), @@ -83,7 +83,7 @@ void QueryResultManager::SetSourcesForCastMode( MediaCastMode cast_mode, const std::vector<MediaSource>& sources, - const GURL& origin) { + const url::Origin& origin) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); if (sources.empty()) { LOG(WARNING) << "SetSourcesForCastMode called with empty sources for " @@ -157,7 +157,7 @@ void QueryResultManager::AddObserversForCastMode( MediaCastMode cast_mode, const std::vector<MediaSource>& sources, - const GURL& origin) { + const url::Origin& origin) { for (const MediaSource& source : sources) { if (!base::ContainsKey(sinks_observers_, source)) { std::unique_ptr<MediaSourceMediaSinksObserver> observer(
diff --git a/chrome/browser/ui/webui/media_router/query_result_manager.h b/chrome/browser/ui/webui/media_router/query_result_manager.h index 553c743..da4681f 100644 --- a/chrome/browser/ui/webui/media_router/query_result_manager.h +++ b/chrome/browser/ui/webui/media_router/query_result_manager.h
@@ -21,7 +21,9 @@ #include "chrome/browser/ui/webui/media_router/media_cast_mode.h" #include "chrome/browser/ui/webui/media_router/media_sink_with_cast_modes.h" -class GURL; +namespace url { +class Origin; +} // namespace url namespace media_router { @@ -36,7 +38,7 @@ // // Typical use: // -// GURL origin("https://origin.com"); +// url::Origin origin{GURL("https://origin.com")}; // QueryResultManager::Observer* observer = ...; // QueryResultManager result_manager(router); // result_manager.AddObserver(observer); @@ -89,7 +91,7 @@ // with another cast mode, no new queries are begun. void SetSourcesForCastMode(MediaCastMode cast_mode, const std::vector<MediaSource>& sources, - const GURL& origin); + const url::Origin& origin); // Stops notifying observers for |cast_mode|, and removes it from the set of // supported cast modes. @@ -127,7 +129,7 @@ // doesn't already have an associated observer. void AddObserversForCastMode(MediaCastMode cast_mode, const std::vector<MediaSource>& sources, - const GURL& origin); + const url::Origin& origin); // Modifies the set of sinks compatible with |cast_mode| and |source| // to |new_sinks|.
diff --git a/chrome/browser/ui/webui/media_router/query_result_manager_unittest.cc b/chrome/browser/ui/webui/media_router/query_result_manager_unittest.cc index 8e01955..8a9bbe98 100644 --- a/chrome/browser/ui/webui/media_router/query_result_manager_unittest.cc +++ b/chrome/browser/ui/webui/media_router/query_result_manager_unittest.cc
@@ -47,7 +47,7 @@ .WillOnce(Return(true)); EXPECT_CALL(mock_observer_, OnResultsUpdated(_)).Times(1); query_result_manager_.SetSourcesForCastMode(cast_mode, {source}, - GURL(kOrigin)); + url::Origin(GURL(kOrigin))); } bool IsDefaultSourceForSink(const MediaSource* source, @@ -108,7 +108,6 @@ } TEST_F(QueryResultManagerTest, StartStopSinksQuery) { - GURL origin(kOrigin); CastModeSet cast_modes = query_result_manager_.GetSupportedCastModes(); EXPECT_TRUE(cast_modes.empty()); std::vector<MediaSource> actual_sources = @@ -119,7 +118,7 @@ EXPECT_CALL(mock_router_, RegisterMediaSinksObserver(_)) .WillOnce(Return(true)); query_result_manager_.SetSourcesForCastMode(MediaCastMode::DEFAULT, {source}, - origin); + url::Origin(GURL(kOrigin))); cast_modes = query_result_manager_.GetSupportedCastModes(); EXPECT_EQ(1u, cast_modes.size()); @@ -135,8 +134,8 @@ EXPECT_CALL(mock_router_, UnregisterMediaSinksObserver(_)).Times(1); EXPECT_CALL(mock_router_, RegisterMediaSinksObserver(_)) .WillOnce(Return(true)); - query_result_manager_.SetSourcesForCastMode(MediaCastMode::DEFAULT, - {another_source}, origin); + query_result_manager_.SetSourcesForCastMode( + MediaCastMode::DEFAULT, {another_source}, url::Origin(GURL(kOrigin))); cast_modes = query_result_manager_.GetSupportedCastModes(); EXPECT_EQ(1u, cast_modes.size()); @@ -167,7 +166,6 @@ MediaSource default_source2 = MediaSourceForPresentationUrl(GURL("http://baz.com")); MediaSource tab_source = MediaSourceForTab(123); - GURL origin(kOrigin); query_result_manager_.AddObserver(&mock_observer_); DiscoverSinks(MediaCastMode::DEFAULT, default_source1); @@ -197,7 +195,7 @@ EXPECT_CALL(mock_observer_, OnResultsUpdated(VectorEquals(expected_sinks))).Times(1); sinks_observer_it->second->OnSinksUpdated(sinks_query_result, - std::vector<GURL>()); + std::vector<url::Origin>()); // Action: TAB_MIRROR -> [2, 3, 4] // Expected result: @@ -226,7 +224,7 @@ EXPECT_CALL(mock_observer_, OnResultsUpdated(VectorEquals(expected_sinks))).Times(1); sinks_observer_it->second->OnSinksUpdated(sinks_query_result, - {GURL(kOrigin)}); + {url::Origin(GURL(kOrigin))}); // Action: Update default presentation URL // Expected result: @@ -246,8 +244,8 @@ .WillOnce(Return(true)); EXPECT_CALL(mock_observer_, OnResultsUpdated(VectorEquals(expected_sinks))).Times(1); - query_result_manager_.SetSourcesForCastMode(MediaCastMode::DEFAULT, - {default_source2}, origin); + query_result_manager_.SetSourcesForCastMode( + MediaCastMode::DEFAULT, {default_source2}, url::Origin(GURL(kOrigin))); // Action: DEFAULT -> [1], origins don't match // Expected result: [2 -> {TAB_MIRROR}, 3 -> {TAB_MIRROR}, 4 -> {TAB_MIRROR}] @@ -260,7 +258,7 @@ EXPECT_CALL(mock_observer_, OnResultsUpdated(VectorEquals(expected_sinks))) .Times(1); sinks_observer_it->second->OnSinksUpdated( - sinks_query_result, {GURL("https://differentOrigin.com")}); + sinks_query_result, {url::Origin(GURL("https://differentOrigin.com"))}); // Action: Remove TAB_MIRROR observer // Expected result: @@ -291,17 +289,16 @@ const std::vector<MediaSource> default_sources = {source_a, source_b, source_c}; const std::vector<MediaSource> tab_sources = {source_tab}; - const GURL origin(kOrigin); const auto& sinks_observers = query_result_manager_.sinks_observers_; // There should be one MediaSinksObserver per source. EXPECT_CALL(mock_router_, RegisterMediaSinksObserver(_)) .Times(4) .WillRepeatedly(Return(true)); - query_result_manager_.SetSourcesForCastMode(MediaCastMode::DEFAULT, - default_sources, origin); - query_result_manager_.SetSourcesForCastMode(MediaCastMode::TAB_MIRROR, - tab_sources, origin); + query_result_manager_.SetSourcesForCastMode( + MediaCastMode::DEFAULT, default_sources, url::Origin(GURL(kOrigin))); + query_result_manager_.SetSourcesForCastMode( + MediaCastMode::TAB_MIRROR, tab_sources, url::Origin(GURL(kOrigin))); // Scenario (results in this order): // Action: URL_B -> [2, 4] @@ -315,7 +312,7 @@ ASSERT_TRUE(sinks_observer_it->second.get()); auto& source_b_observer = sinks_observer_it->second; - source_b_observer->OnSinksUpdated({sink2, sink4}, std::vector<GURL>()); + source_b_observer->OnSinksUpdated({sink2, sink4}, std::vector<url::Origin>()); EXPECT_TRUE(IsDefaultSourceForSink(nullptr, sink1)); EXPECT_TRUE(IsDefaultSourceForSink(&source_b, sink2)); EXPECT_TRUE(IsDefaultSourceForSink(nullptr, sink3)); @@ -332,7 +329,8 @@ ASSERT_TRUE(sinks_observer_it->second.get()); auto& source_c_observer = sinks_observer_it->second; - source_c_observer->OnSinksUpdated({sink1, sink2, sink3}, std::vector<GURL>()); + source_c_observer->OnSinksUpdated({sink1, sink2, sink3}, + std::vector<url::Origin>()); EXPECT_TRUE(IsDefaultSourceForSink(&source_c, sink1)); EXPECT_TRUE(IsDefaultSourceForSink(&source_b, sink2)); EXPECT_TRUE(IsDefaultSourceForSink(&source_c, sink3)); @@ -349,7 +347,8 @@ ASSERT_TRUE(sinks_observer_it->second.get()); auto& source_a_observer = sinks_observer_it->second; - source_a_observer->OnSinksUpdated({sink2, sink3, sink4}, std::vector<GURL>()); + source_a_observer->OnSinksUpdated({sink2, sink3, sink4}, + std::vector<url::Origin>()); EXPECT_TRUE(IsDefaultSourceForSink(&source_c, sink1)); EXPECT_TRUE(IsDefaultSourceForSink(&source_a, sink2)); EXPECT_TRUE(IsDefaultSourceForSink(&source_a, sink3)); @@ -366,7 +365,8 @@ ASSERT_TRUE(sinks_observer_it->second.get()); auto& source_tab_observer = sinks_observer_it->second; - source_tab_observer->OnSinksUpdated({sink1, sink2}, std::vector<GURL>()); + source_tab_observer->OnSinksUpdated({sink1, sink2}, + std::vector<url::Origin>()); EXPECT_TRUE(IsDefaultSourceForSink(&source_c, sink1)); EXPECT_TRUE(IsDefaultSourceForSink(&source_a, sink2)); EXPECT_TRUE(IsDefaultSourceForSink(&source_a, sink3)); @@ -385,17 +385,16 @@ TEST_F(QueryResultManagerTest, AddInvalidSource) { const MediaSource source( MediaSourceForPresentationUrl(GURL("http://url.com"))); - const GURL origin(kOrigin); EXPECT_CALL(mock_router_, RegisterMediaSinksObserver(_)) .Times(1) .WillRepeatedly(Return(true)); query_result_manager_.SetSourcesForCastMode(MediaCastMode::DEFAULT, {source}, - origin); + url::Origin(GURL(kOrigin))); // |source| has already been registered with the default cast mode, so it // shouldn't get registered with tab mirroring. - query_result_manager_.SetSourcesForCastMode(MediaCastMode::TAB_MIRROR, - {source}, origin); + query_result_manager_.SetSourcesForCastMode( + MediaCastMode::TAB_MIRROR, {source}, url::Origin(GURL(kOrigin))); const auto& cast_mode_sources = query_result_manager_.cast_mode_sources_; const auto& default_sources = cast_mode_sources.at(MediaCastMode::DEFAULT);
diff --git a/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc b/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc index e12782d..9ae0657 100644 --- a/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc +++ b/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc
@@ -9,7 +9,6 @@ #include "chrome/browser/favicon/favicon_service_factory.h" #include "chrome/browser/history/top_sites_factory.h" #include "chrome/browser/ntp_tiles/chrome_most_visited_sites_factory.h" -#include "chrome/browser/ntp_tiles/chrome_popular_sites_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search/suggestions/image_decoder_impl.h" #include "chrome/browser/search/suggestions/suggestions_service_factory.h" @@ -45,7 +44,6 @@ bool SupportsNTPTiles() override; bool DoesSourceExist(ntp_tiles::NTPTileSource source) override; std::unique_ptr<ntp_tiles::MostVisitedSites> MakeMostVisitedSites() override; - std::unique_ptr<ntp_tiles::PopularSites> MakePopularSites() override; PrefService* GetPrefs() override; void RegisterMessageCallback( const std::string& message, @@ -92,15 +90,6 @@ Profile::FromWebUI(web_ui())); } -std::unique_ptr<ntp_tiles::PopularSites> -ChromeNTPTilesInternalsMessageHandlerClient::MakePopularSites() { -#if defined(OS_ANDROID) - return ChromePopularSitesFactory::NewForProfile(Profile::FromWebUI(web_ui())); -#else - return nullptr; -#endif -} - PrefService* ChromeNTPTilesInternalsMessageHandlerClient::GetPrefs() { return Profile::FromWebUI(web_ui())->GetPrefs(); }
diff --git a/chrome/browser/ui/webui/options/chromeos/options_stylus_handler.cc b/chrome/browser/ui/webui/options/chromeos/options_stylus_handler.cc index 44d319ea..725a703b 100644 --- a/chrome/browser/ui/webui/options/chromeos/options_stylus_handler.cc +++ b/chrome/browser/ui/webui/options/chromeos/options_stylus_handler.cc
@@ -9,6 +9,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/grit/generated_resources.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/events/devices/input_device_manager.h" namespace chromeos { namespace options { @@ -24,9 +25,11 @@ OptionsStylusHandler::OptionsStylusHandler() : weak_ptr_factory_(this) { NoteTakingHelper::Get()->AddObserver(this); + ui::InputDeviceManager::GetInstance()->AddObserver(this); } OptionsStylusHandler::~OptionsStylusHandler() { + ui::InputDeviceManager::GetInstance()->RemoveObserver(this); NoteTakingHelper::Get()->RemoveObserver(this); } @@ -60,9 +63,6 @@ "stylusNoteTakingAppWaitingForAndroid", l10n_util::GetStringUTF16( IDS_OPTIONS_STYLUS_NOTE_TAKING_APP_WAITING_FOR_ANDROID)); - - localized_strings->SetBoolean("showStylusSettings", - ash::IsPaletteFeatureEnabled()); } void OptionsStylusHandler::InitializePage() { @@ -74,12 +74,34 @@ "setPreferredNoteTakingApp", base::Bind(&OptionsStylusHandler::SetPreferredNoteTakingApp, weak_ptr_factory_.GetWeakPtr())); + web_ui()->RegisterMessageCallback( + "requestStylusHardwareState", + base::Bind(&OptionsStylusHandler::RequestStylusHardwareState, + weak_ptr_factory_.GetWeakPtr())); } void OptionsStylusHandler::OnAvailableNoteTakingAppsUpdated() { UpdateNoteTakingApps(); } +void OptionsStylusHandler::OnDeviceListsComplete() { + SendHasStylus(); +} + +void OptionsStylusHandler::RequestStylusHardwareState( + const base::ListValue* args) { + if (ui::InputDeviceManager::GetInstance()->AreDeviceListsComplete()) + SendHasStylus(); +} + +void OptionsStylusHandler::SendHasStylus() { + DCHECK(ui::InputDeviceManager::GetInstance()->AreDeviceListsComplete()); + + web_ui()->CallJavascriptFunctionUnsafe( + "BrowserOptions.setStylusInputStatus", + base::FundamentalValue(ash::palette_utils::HasStylusInput())); +} + void OptionsStylusHandler::UpdateNoteTakingApps() { bool waiting_for_android = false; note_taking_app_ids_.clear();
diff --git a/chrome/browser/ui/webui/options/chromeos/options_stylus_handler.h b/chrome/browser/ui/webui/options/chromeos/options_stylus_handler.h index a35595a..6e729c6 100644 --- a/chrome/browser/ui/webui/options/chromeos/options_stylus_handler.h +++ b/chrome/browser/ui/webui/options/chromeos/options_stylus_handler.h
@@ -12,6 +12,7 @@ #include "base/memory/weak_ptr.h" #include "chrome/browser/chromeos/note_taking_helper.h" #include "chrome/browser/ui/webui/options/options_ui.h" +#include "ui/events/devices/input_device_event_observer.h" namespace base { class ListValue; @@ -22,7 +23,8 @@ // Stylus-specific options C++ code. class OptionsStylusHandler : public ::options::OptionsPageUIHandler, - public NoteTakingHelper::Observer { + public NoteTakingHelper::Observer, + public ui::InputDeviceEventObserver { public: OptionsStylusHandler(); ~OptionsStylusHandler() override; @@ -35,7 +37,17 @@ // NoteTakingHelper::Observer implementation. void OnAvailableNoteTakingAppsUpdated() override; + // ui::InputDeviceEventObserver implementation: + void OnDeviceListsComplete() override; + private: + // Called from WebUI when the page is initialized to determine if stylus + // settings should be shown. + void RequestStylusHardwareState(const base::ListValue* args); + + // Sends if there is a stylus device to WebUI. + void SendHasStylus(); + // Updates the note-taking app menu in the stylus overlay to display the // currently-available set of apps. void UpdateNoteTakingApps();
diff --git a/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.cc b/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.cc index 1ee3967..40d1c5d3 100644 --- a/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.cc +++ b/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.cc
@@ -35,7 +35,6 @@ #include "components/drive/chromeos/file_system_interface.h" #include "components/user_manager/user_manager.h" #include "content/public/browser/browser_context.h" -#include "content/public/browser/browser_thread.h" #include "content/public/browser/storage_partition.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/text/bytes_formatting.h" @@ -251,9 +250,9 @@ const base::FilePath downloads_path = file_manager::util::GetDownloadsFolderForProfile(profile); - base::PostTaskAndReplyWithResult( - content::BrowserThread::GetBlockingPool(), - FROM_HERE, + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, base::TaskTraits().MayBlock().WithPriority( + base::TaskPriority::BACKGROUND), base::Bind(&base::ComputeDirectorySize, downloads_path), base::Bind(&StorageManagerHandler::OnGetDownloadsSize, weak_ptr_factory_.GetWeakPtr()));
diff --git a/chrome/browser/ui/webui/options/manage_profile_handler.cc b/chrome/browser/ui/webui/options/manage_profile_handler.cc index f7a59af..e8403f8 100644 --- a/chrome/browser/ui/webui/options/manage_profile_handler.cc +++ b/chrome/browser/ui/webui/options/manage_profile_handler.cc
@@ -307,8 +307,7 @@ ProfileAttributesEntry* entry = nullptr; bool success = storage.GetProfileAttributesWithPath(profile->GetPath(), &entry); - DCHECK(success); - const gfx::Image* icon = entry->GetGAIAPicture(); + const gfx::Image* icon = success ? entry->GetGAIAPicture() : nullptr; if (icon) { gfx::Image icon2 = profiles::GetAvatarIconForWebUI(*icon, true); gaia_picture_url_ = webui::GetBitmapDataUrl(icon2.AsBitmap());
diff --git a/chrome/browser/ui/webui/password_manager_internals/OWNERS b/chrome/browser/ui/webui/password_manager_internals/OWNERS index 5296ea4..e8e1954b 100644 --- a/chrome/browser/ui/webui/password_manager_internals/OWNERS +++ b/chrome/browser/ui/webui/password_manager_internals/OWNERS
@@ -1,2 +1,4 @@ mkwst@chromium.org vabr@chromium.org + +# COMPONENT: UI>Browser>Passwords
diff --git a/chrome/browser/ui/webui/popular_sites_internals_ui.cc b/chrome/browser/ui/webui/popular_sites_internals_ui.cc index 1c702c0..88e0779 100644 --- a/chrome/browser/ui/webui/popular_sites_internals_ui.cc +++ b/chrome/browser/ui/webui/popular_sites_internals_ui.cc
@@ -31,7 +31,6 @@ void RegisterMessages() override; // ntp_tiles::PopularSitesInternalsMessageHandlerClient - base::SequencedWorkerPool* GetBlockingPool() override; std::unique_ptr<ntp_tiles::PopularSites> MakePopularSites() override; PrefService* GetPrefs() override; void RegisterMessageCallback( @@ -50,11 +49,6 @@ handler_.RegisterMessages(); } -base::SequencedWorkerPool* -ChromePopularSitesInternalsMessageHandlerBridge::GetBlockingPool() { - return content::BrowserThread::GetBlockingPool(); -} - std::unique_ptr<ntp_tiles::PopularSites> ChromePopularSitesInternalsMessageHandlerBridge::MakePopularSites() { return ChromePopularSitesFactory::NewForProfile(Profile::FromWebUI(web_ui()));
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.cc b/chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.cc index f2db088..bbd8910 100644 --- a/chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.cc
@@ -4,7 +4,10 @@ #include "chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.h" +#include "ash/common/system/chromeos/palette/palette_utils.h" +#include "base/bind.h" #include "chrome/browser/profiles/profile.h" +#include "ui/events/devices/input_device_manager.h" namespace chromeos { namespace settings { @@ -20,9 +23,11 @@ StylusHandler::StylusHandler() { NoteTakingHelper::Get()->AddObserver(this); + ui::InputDeviceManager::GetInstance()->AddObserver(this); } StylusHandler::~StylusHandler() { + ui::InputDeviceManager::GetInstance()->RemoveObserver(this); NoteTakingHelper::Get()->RemoveObserver(this); } @@ -30,6 +35,9 @@ DCHECK(web_ui()); web_ui()->RegisterMessageCallback( + "initializeStylusSettings", + base::Bind(&StylusHandler::HandleInitialize, base::Unretained(this))); + web_ui()->RegisterMessageCallback( "requestNoteTakingApps", base::Bind(&StylusHandler::RequestApps, base::Unretained(this))); web_ui()->RegisterMessageCallback( @@ -42,6 +50,10 @@ UpdateNoteTakingApps(); } +void StylusHandler::OnDeviceListsComplete() { + SendHasStylus(); +} + void StylusHandler::UpdateNoteTakingApps() { bool waiting_for_android = false; note_taking_app_ids_.clear(); @@ -91,5 +103,18 @@ app_id); } +void StylusHandler::HandleInitialize(const base::ListValue* args) { + AllowJavascript(); + if (ui::InputDeviceManager::GetInstance()->AreDeviceListsComplete()) + SendHasStylus(); +} + +void StylusHandler::SendHasStylus() { + DCHECK(ui::InputDeviceManager::GetInstance()->AreDeviceListsComplete()); + CallJavascriptFunction( + "cr.webUIListenerCallback", base::StringValue("has-stylus-changed"), + base::FundamentalValue(ash::palette_utils::HasStylusInput())); +} + } // namespace settings } // namespace chromeos
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.h b/chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.h index c950ffff..a21c40e 100644 --- a/chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.h +++ b/chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.h
@@ -10,12 +10,19 @@ #include "base/macros.h" #include "chrome/browser/chromeos/note_taking_helper.h" #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" +#include "ui/events/devices/input_device_event_observer.h" + +namespace base { +class ListValue; +} namespace chromeos { namespace settings { +// Chrome OS stylus settings handler. class StylusHandler : public ::settings::SettingsPageUIHandler, - public chromeos::NoteTakingHelper::Observer { + public chromeos::NoteTakingHelper::Observer, + public ui::InputDeviceEventObserver { public: StylusHandler(); ~StylusHandler() override; @@ -28,11 +35,19 @@ // chromeos::NoteTakingHelper::Observer implementation. void OnAvailableNoteTakingAppsUpdated() override; + // ui::InputDeviceObserver: + void OnDeviceListsComplete() override; + private: void UpdateNoteTakingApps(); void RequestApps(const base::ListValue* unused_args); void SetPreferredNoteTakingApp(const base::ListValue* args); + // Called by JS to request a |SendHasStylus| call. + void HandleInitialize(const base::ListValue* args); + // Enables or disables the stylus UI section. + void SendHasStylus(); + // IDs of available note-taking apps. std::set<std::string> note_taking_app_ids_;
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc index 6485df3e9..e5a9ae4 100644 --- a/chrome/browser/ui/webui/settings/md_settings_ui.cc +++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -159,7 +159,8 @@ AddSettingsPageUIHandler(base::WrapUnique( chromeos::settings::DateTimeHandler::Create(html_source))); - html_source->AddBoolean("stylusAllowed", ash::IsPaletteFeatureEnabled()); + AddSettingsPageUIHandler( + base::MakeUnique<chromeos::settings::StylusHandler>()); html_source->AddBoolean("pinUnlockEnabled", chromeos::IsPinUnlockEnabled(profile->GetPrefs())); html_source->AddBoolean("fingerprintUnlockEnabled",
diff --git a/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc b/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc index 5cae011..cf503a72 100644 --- a/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc +++ b/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
@@ -763,6 +763,7 @@ web_ui()->RegisterMessageCallback("loginVisible", kDoNothingCallback); // Unused callbacks from user_pod_row.js web_ui()->RegisterMessageCallback("focusPod", kDoNothingCallback); + web_ui()->RegisterMessageCallback("noPodFocused", kDoNothingCallback); } void UserManagerScreenHandler::GetLocalizedValues(
diff --git a/chrome/browser/ui/webui/version_handler_chromeos.cc b/chrome/browser/ui/webui/version_handler_chromeos.cc index 09c446a..cd9ab7f 100644 --- a/chrome/browser/ui/webui/version_handler_chromeos.cc +++ b/chrome/browser/ui/webui/version_handler_chromeos.cc
@@ -5,8 +5,7 @@ #include "chrome/browser/ui/webui/version_handler_chromeos.h" #include "base/bind.h" -#include "base/task_runner_util.h" -#include "content/public/browser/browser_thread.h" +#include "base/task_scheduler/post_task.h" #include "content/public/browser/web_ui.h" VersionHandlerChromeOS::VersionHandlerChromeOS() @@ -19,16 +18,16 @@ void VersionHandlerChromeOS::HandleRequestVersionInfo( const base::ListValue* args) { // Start the asynchronous load of the versions. - base::PostTaskAndReplyWithResult( - content::BrowserThread::GetBlockingPool(), - FROM_HERE, + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, base::TaskTraits().MayBlock().WithPriority( + base::TaskPriority::BACKGROUND), base::Bind(&chromeos::version_loader::GetVersion, chromeos::version_loader::VERSION_FULL), base::Bind(&VersionHandlerChromeOS::OnVersion, weak_factory_.GetWeakPtr())); - base::PostTaskAndReplyWithResult( - content::BrowserThread::GetBlockingPool(), - FROM_HERE, + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, base::TaskTraits().MayBlock().WithPriority( + base::TaskPriority::BACKGROUND), base::Bind(&chromeos::version_loader::GetARCVersion), base::Bind(&VersionHandlerChromeOS::OnARCVersion, weak_factory_.GetWeakPtr()));
diff --git a/chrome/browser/ui/webui/webapks_handler.cc b/chrome/browser/ui/webui/webapks_handler.cc new file mode 100644 index 0000000..69d98c8 --- /dev/null +++ b/chrome/browser/ui/webui/webapks_handler.cc
@@ -0,0 +1,44 @@ +// 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/webui/webapks_handler.h" + +#include "base/callback_forward.h" +#include "base/values.h" +#include "chrome/browser/android/shortcut_helper.h" +#include "content/public/browser/web_ui.h" + +WebApksHandler::WebApksHandler() : weak_ptr_factory_(this) {} + +WebApksHandler::~WebApksHandler() {} + +void WebApksHandler::RegisterMessages() { + web_ui()->RegisterMessageCallback( + "requestWebApksInfo", + base::Bind(&WebApksHandler::HandleRequestWebApksInfo, + base::Unretained(this))); +} + +void WebApksHandler::HandleRequestWebApksInfo(const base::ListValue* args) { + AllowJavascript(); + ShortcutHelper::RetrieveWebApks(base::Bind( + &WebApksHandler::OnWebApkInfoRetrieved, weak_ptr_factory_.GetWeakPtr())); +} + +void WebApksHandler::OnWebApkInfoRetrieved( + const std::vector<WebApkInfo>& webapks_list) { + if (!IsJavascriptAllowed()) + return; + base::ListValue list; + for (const auto& webapk_info : webapks_list) { + std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue()); + result->SetString("shortName", webapk_info.short_name); + result->SetString("packageName", webapk_info.package_name); + result->SetInteger("shellApkVersion", webapk_info.shell_apk_version); + result->SetInteger("versionCode", webapk_info.version_code); + list.Append(std::move(result)); + } + + CallJavascriptFunction("returnWebApksInfo", list); +}
diff --git a/chrome/browser/ui/webui/webapks_handler.h b/chrome/browser/ui/webui/webapks_handler.h new file mode 100644 index 0000000..7d051ee8 --- /dev/null +++ b/chrome/browser/ui/webui/webapks_handler.h
@@ -0,0 +1,43 @@ +// 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 CHROME_BROWSER_UI_WEBUI_WEBAPKS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_WEBAPKS_HANDLER_H_ + +#include <vector> + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/android/webapk/webapk_info.h" +#include "content/public/browser/web_ui_message_handler.h" + +namespace base { +class ListValue; +} // namespace base + +// Handles JavaScript messages from the chrome://webapks page. +class WebApksHandler : public content::WebUIMessageHandler { + public: + WebApksHandler(); + ~WebApksHandler() override; + + // content::WebUIMessageHandler: + void RegisterMessages() override; + + // Handler for the "requestWebApksInfo" message. This requests + // information for the installed WebAPKs and returns it to JS using + // OnWebApkInfoReceived(). + virtual void HandleRequestWebApksInfo(const base::ListValue* args); + + private: + // Sends information for the installed WebAPKs to JS. + void OnWebApkInfoRetrieved(const std::vector<WebApkInfo>& webapks_list); + + // Factory for the creating refs in callbacks. + base::WeakPtrFactory<WebApksHandler> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(WebApksHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_WEBAPKS_HANDLER_H_
diff --git a/chrome/browser/ui/webui/webapks_ui.cc b/chrome/browser/ui/webui/webapks_ui.cc new file mode 100644 index 0000000..d71329302 --- /dev/null +++ b/chrome/browser/ui/webui/webapks_ui.cc
@@ -0,0 +1,43 @@ +// 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/webui/webapks_ui.h" + +#include <string> +#include <unordered_set> + +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/webapks_handler.h" +#include "chrome/common/url_constants.h" +#include "chrome/grit/webapks_ui_resources.h" +#include "components/grit/components_resources.h" +#include "content/public/browser/web_ui.h" +#include "content/public/browser/web_ui_data_source.h" + +using content::WebUIDataSource; + +namespace { + +WebUIDataSource* CreateWebApksUIDataSource() { + WebUIDataSource* html_source = + WebUIDataSource::Create(chrome::kChromeUIWebApksHost); + html_source->SetJsonPath("strings.js"); + html_source->AddResourcePath("webapks.js", IDR_WEBAPKS_UI_JS); + html_source->AddResourcePath("about_webapks.css", IDR_WEBAPKS_UI_CSS); + html_source->SetDefaultResource(IDR_WEBAPKS_UI_HTML); + html_source->UseGzip(std::unordered_set<std::string>()); + + return html_source; +} + +} // anonymous namespace + +WebApksUI::WebApksUI(content::WebUI* web_ui) + : content::WebUIController(web_ui) { + Profile* profile = Profile::FromWebUI(web_ui); + web_ui->AddMessageHandler(base::MakeUnique<WebApksHandler>()); + WebUIDataSource::Add(profile, CreateWebApksUIDataSource()); +} + +WebApksUI::~WebApksUI() {}
diff --git a/chrome/browser/ui/webui/webapks_ui.h b/chrome/browser/ui/webui/webapks_ui.h new file mode 100644 index 0000000..c2a1f0c9 --- /dev/null +++ b/chrome/browser/ui/webui/webapks_ui.h
@@ -0,0 +1,21 @@ +// 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 CHROME_BROWSER_UI_WEBUI_WEBAPKS_UI_H_ +#define CHROME_BROWSER_UI_WEBUI_WEBAPKS_UI_H_ + +#include "base/macros.h" +#include "content/public/browser/web_ui_controller.h" + +// The WebUI handler for chrome://webapks. +class WebApksUI : public content::WebUIController { + public: + explicit WebApksUI(content::WebUI* web_ui); + ~WebApksUI() override; + + private: + DISALLOW_COPY_AND_ASSIGN(WebApksUI); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_WEBAPKS_UI_H_
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni index 1ecd49b..27c28f32 100644 --- a/chrome/chrome_paks.gni +++ b/chrome/chrome_paks.gni
@@ -168,6 +168,10 @@ ] deps += [ "//extensions:extensions_resources" ] } + if (is_android) { + sources += [ "$root_gen_dir/chrome/webapks_ui_resources.pak" ] + deps += [ "//chrome/browser/resources:webapks_ui_resources" ] + } } }
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json index 06c40e0..bae83040 100644 --- a/chrome/common/extensions/api/_api_features.json +++ b/chrome/common/extensions/api/_api_features.json
@@ -745,11 +745,17 @@ "dependencies": ["permission:tabCapture"], "contexts": ["blessed_extension"] }, - "tabs": { + "tabs": [{ "channel": "stable", "extension_types": ["extension", "legacy_packaged_app"], "contexts": ["blessed_extension", "extension_service_worker"] - }, + }, { + "channel": "stable", + "contexts": ["webui"], + "matches": [ + "chrome://bookmarks/*" + ] + }], "terminalPrivate": { "dependencies": ["permission:terminalPrivate"], "contexts": ["blessed_extension"]
diff --git a/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc b/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc index 0e50db9..4f05e00 100644 --- a/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc +++ b/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc
@@ -101,12 +101,15 @@ return std::move(overrides->search_provider); } -// A www. prefix is not informative and thus not worth the limited real estate -// in the permissions UI. -std::string RemoveWwwPrefix(const std::string& url) { - if (base::StartsWith(url, kWwwPrefix, base::CompareCase::INSENSITIVE_ASCII)) - return url.substr(strlen(kWwwPrefix)); - return url; +std::string FormatUrlForDisplay(const GURL& url) { + base::StringPiece host = url.host_piece(); + // A www. prefix is not informative and thus not worth the limited real estate + // in the permissions UI. + base::StringPiece formatted_host = + base::StartsWith(host, kWwwPrefix, base::CompareCase::INSENSITIVE_ASCII) + ? host.substr(strlen(kWwwPrefix)) + : host; + return formatted_host.as_string(); } } // namespace @@ -148,13 +151,11 @@ if (info->search_engine) { PermissionsParser::AddAPIPermission( - extension, - new SettingsOverrideAPIPermission( - PermissionsInfo::GetInstance()->GetByID( - APIPermission::kSearchProvider), - RemoveWwwPrefix(CreateManifestURL(info->search_engine->search_url) - ->GetOrigin() - .host()))); + extension, new SettingsOverrideAPIPermission( + PermissionsInfo::GetInstance()->GetByID( + APIPermission::kSearchProvider), + FormatUrlForDisplay(*CreateManifestURL( + info->search_engine->search_url)))); } if (!info->startup_pages.empty()) { PermissionsParser::AddAPIPermission( @@ -163,16 +164,15 @@ PermissionsInfo::GetInstance()->GetByID( APIPermission::kStartupPages), // We only support one startup page even though the type of the - // manifest - // property is a list, only the first one is used. - RemoveWwwPrefix(info->startup_pages[0].GetContent()))); + // manifest property is a list, only the first one is used. + FormatUrlForDisplay(info->startup_pages[0]))); } if (info->homepage) { PermissionsParser::AddAPIPermission( extension, new SettingsOverrideAPIPermission( PermissionsInfo::GetInstance()->GetByID(APIPermission::kHomepage), - RemoveWwwPrefix(info->homepage->GetContent()))); + FormatUrlForDisplay(*(info->homepage)))); } extension->SetManifestData(manifest_keys::kSettingsOverride, info.release());
diff --git a/chrome/common/extensions/permissions/settings_override_permission_unittest.cc b/chrome/common/extensions/permissions/settings_override_permission_unittest.cc index 266bb88..421a01d8 100644 --- a/chrome/common/extensions/permissions/settings_override_permission_unittest.cc +++ b/chrome/common/extensions/permissions/settings_override_permission_unittest.cc
@@ -49,7 +49,7 @@ std::unique_ptr<base::DictionaryValue> settings_override( new base::DictionaryValue); if (flags & kHomepage) - settings_override->SetString("homepage", "http://www.google.com"); + settings_override->SetString("homepage", "http://www.google.com/home"); if (flags & kStartupPages) { std::unique_ptr<base::ListValue> startup_pages(new base::ListValue); startup_pages->AppendString("http://startup.com/startup.html"); @@ -88,7 +88,7 @@ #if defined(OS_WIN) || defined(OS_MACOSX) EXPECT_TRUE(permission_set.HasAPIPermission(APIPermission::kHomepage)); VerifyOnePermissionMessage(extension->permissions_data(), - "Change your home page to: google.com/"); + "Change your home page to: google.com"); #else EXPECT_FALSE(permission_set.HasAPIPermission(APIPermission::kHomepage)); #endif @@ -104,9 +104,8 @@ #if defined(OS_WIN) || defined(OS_MACOSX) EXPECT_TRUE(permission_set.HasAPIPermission(APIPermission::kStartupPages)); - VerifyOnePermissionMessage( - extension->permissions_data(), - "Change your start page to: startup.com/startup.html"); + VerifyOnePermissionMessage(extension->permissions_data(), + "Change your start page to: startup.com"); #else EXPECT_FALSE(permission_set.HasAPIPermission(APIPermission::kStartupPages)); #endif
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 7b14c9a..6d0a7b30 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc
@@ -68,6 +68,10 @@ // This is the URL of the page to load when opening new tabs. const char kHomePage[] = "homepage"; +// Stores information about the important sites dialog, including the time and +// frequency it has been ignored. +const char kImportantSitesDialogHistory[] = "important_sites_dialog"; + #if defined(OS_WIN) // This is a timestamp of the last time this profile was reset by a third party // tool. On Windows, a third party tool may set a registry value that will be
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 1dbaadaf..96517ce 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -36,6 +36,7 @@ extern const char kForceEphemeralProfiles[]; extern const char kHomePageIsNewTabPage[]; extern const char kHomePage[]; +extern const char kImportantSitesDialogHistory[]; #if defined(OS_WIN) extern const char kLastProfileResetTimestamp[]; #endif
diff --git a/chrome/common/resource_usage_reporter_type_converters.h b/chrome/common/resource_usage_reporter_type_converters.h index 3beda3ff..1901eb1 100644 --- a/chrome/common/resource_usage_reporter_type_converters.h +++ b/chrome/common/resource_usage_reporter_type_converters.h
@@ -7,7 +7,7 @@ #include "chrome/common/resource_usage_reporter.mojom.h" #include "mojo/public/cpp/bindings/type_converter.h" -#include "third_party/WebKit/public/web/WebCache.h" +#include "third_party/WebKit/public/platform/WebCache.h" namespace mojo {
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc index 829a236..462c47d 100644 --- a/chrome/common/url_constants.cc +++ b/chrome/common/url_constants.cc
@@ -108,10 +108,10 @@ const char kChromeUINativeScheme[] = "chrome-native"; const char kChromeUINativeNewTabURL[] = "chrome-native://newtab/"; const char kChromeUINativeBookmarksURL[] = "chrome-native://bookmarks/"; -const char kChromeUINativeHistoryURL[] = "chrome-native://history/"; const char kChromeUINativePhysicalWebDiagnosticsURL[] = "chrome-native://physical-web-diagnostics/"; const char kChromeUINativeRecentTabsURL[] = "chrome-native://recent-tabs/"; +const char kChromeUIWebApksURL[] = "chrome://webapks/"; #endif #if defined(OS_CHROMEOS) @@ -287,6 +287,7 @@ const char kChromeUIPhysicalWebDiagnosticsHost[] = "physical-web-diagnostics"; const char kChromeUIPopularSitesInternalsHost[] = "popular-sites-internals"; const char kChromeUISnippetsInternalsHost[] = "snippets-internals"; +const char kChromeUIWebApksHost[] = "webapks"; #endif #if defined(ENABLE_VR_SHELL) || defined(ENABLE_WEBVR) @@ -690,6 +691,7 @@ kChromeUIOfflineInternalsHost, kChromeUIPopularSitesInternalsHost, kChromeUISnippetsInternalsHost, + kChromeUIWebApksHost, #endif #if defined(OS_CHROMEOS) kChromeUICertificateManagerHost,
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h index d5d54031..0bfe923 100644 --- a/chrome/common/url_constants.h +++ b/chrome/common/url_constants.h
@@ -98,9 +98,9 @@ extern const char kChromeUINativeScheme[]; extern const char kChromeUINativeNewTabURL[]; extern const char kChromeUINativeBookmarksURL[]; -extern const char kChromeUINativeHistoryURL[]; extern const char kChromeUINativePhysicalWebDiagnosticsURL[]; extern const char kChromeUINativeRecentTabsURL[]; +extern const char kChromeUIWebApksURL[]; #endif // defined(OS_ANDROID) #if defined(OS_CHROMEOS) @@ -266,6 +266,7 @@ extern const char kChromeUIPhysicalWebDiagnosticsHost[]; extern const char kChromeUIPopularSitesInternalsHost[]; extern const char kChromeUISnippetsInternalsHost[]; +extern const char kChromeUIWebApksHost[]; #endif #if defined(ENABLE_VR_SHELL) || defined(ENABLE_WEBVR)
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc index 1b843409..3e7415b3 100644 --- a/chrome/installer/setup/setup_main.cc +++ b/chrome/installer/setup/setup_main.cc
@@ -214,8 +214,8 @@ // Returns the MSI product ID from the ClientState key that is populated for MSI // installs. This property is encoded in a value name whose format is -// "EnterpriseId<GUID>" where <GUID> is the MSI product id. <GUID> is in the -// format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. The id will be returned if +// "EnterpriseProduct<GUID>" where <GUID> is the MSI product id. <GUID> is in +// the format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. The id will be returned if // found otherwise this method will return an empty string. // // This format is strange and its provenance is shrouded in mystery but it has @@ -226,8 +226,8 @@ BrowserDistribution* dist = product.distribution(); DCHECK(dist); - base::win::RegistryValueIterator value_iter(reg_root, - dist->GetStateKey().c_str()); + base::win::RegistryValueIterator value_iter( + reg_root, dist->GetStateKey().c_str(), KEY_WOW64_32KEY); for (; value_iter.Valid(); ++value_iter) { base::string16 value_name(value_iter.Name()); if (base::StartsWith(value_name, kMsiProductIdPrefix,
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc index 12162cf..a4f67e1 100644 --- a/chrome/renderer/chrome_content_renderer_client.cc +++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -104,13 +104,13 @@ #include "printing/features/features.h" #include "services/service_manager/public/cpp/interface_provider.h" #include "third_party/WebKit/public/platform/URLConversion.h" +#include "third_party/WebKit/public/platform/WebCache.h" #include "third_party/WebKit/public/platform/WebCachePolicy.h" #include "third_party/WebKit/public/platform/WebSecurityOrigin.h" #include "third_party/WebKit/public/platform/WebURL.h" #include "third_party/WebKit/public/platform/WebURLError.h" #include "third_party/WebKit/public/platform/WebURLRequest.h" #include "third_party/WebKit/public/platform/WebURLResponse.h" -#include "third_party/WebKit/public/web/WebCache.h" #include "third_party/WebKit/public/web/WebDataSource.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebElement.h"
diff --git a/chrome/renderer/chrome_render_frame_observer.cc b/chrome/renderer/chrome_render_frame_observer.cc index 23026a0..729e75b 100644 --- a/chrome/renderer/chrome_render_frame_observer.cc +++ b/chrome/renderer/chrome_render_frame_observer.cc
@@ -251,7 +251,8 @@ } } -void ChromeRenderFrameObserver::DidStartProvisionalLoad() { +void ChromeRenderFrameObserver::DidStartProvisionalLoad( + blink::WebDataSource* data_source) { // Let translate_helper do any preparatory work for loading a URL. if (!translate_helper_) return;
diff --git a/chrome/renderer/chrome_render_frame_observer.h b/chrome/renderer/chrome_render_frame_observer.h index fe47f6c7..a9dad7bb 100644 --- a/chrome/renderer/chrome_render_frame_observer.h +++ b/chrome/renderer/chrome_render_frame_observer.h
@@ -34,7 +34,7 @@ // RenderFrameObserver implementation. bool OnMessageReceived(const IPC::Message& message) override; - void DidStartProvisionalLoad() override; + void DidStartProvisionalLoad(blink::WebDataSource* data_source) override; void DidFinishLoad() override; void DidCommitProvisionalLoad(bool is_new_navigation, bool is_same_page_navigation) override;
diff --git a/chrome/renderer/chrome_render_thread_observer.cc b/chrome/renderer/chrome_render_thread_observer.cc index 6602fa2..ebfe329 100644 --- a/chrome/renderer/chrome_render_thread_observer.cc +++ b/chrome/renderer/chrome_render_thread_observer.cc
@@ -53,7 +53,7 @@ #include "net/base/net_module.h" #include "services/service_manager/public/cpp/interface_provider.h" #include "services/service_manager/public/cpp/interface_registry.h" -#include "third_party/WebKit/public/web/WebCache.h" +#include "third_party/WebKit/public/platform/WebCache.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
diff --git a/chrome/renderer/net/net_error_helper.cc b/chrome/renderer/net/net_error_helper.cc index 1c3d935..e8ee1d95 100644 --- a/chrome/renderer/net/net_error_helper.cc +++ b/chrome/renderer/net/net_error_helper.cc
@@ -66,9 +66,9 @@ // suggestions. If it takes too long, just use the local error page. const int kNavigationCorrectionFetchTimeoutSec = 3; -NetErrorHelperCore::PageType GetLoadingPageType(RenderFrame* render_frame) { - blink::WebFrame* web_frame = render_frame->GetWebFrame(); - GURL url = web_frame->provisionalDataSource()->getRequest().url(); +NetErrorHelperCore::PageType GetLoadingPageType( + blink::WebDataSource* data_source) { + GURL url = data_source->getRequest().url(); if (!url.is_valid() || url.spec() != kUnreachableWebDataURL) return NetErrorHelperCore::NON_ERROR_PAGE; return NetErrorHelperCore::ERROR_PAGE; @@ -118,9 +118,10 @@ core_->TrackClick(tracking_id); } -void NetErrorHelper::DidStartProvisionalLoad() { +void NetErrorHelper::DidStartProvisionalLoad( + blink::WebDataSource* data_source) { core_->OnStartLoad(GetFrameType(render_frame()), - GetLoadingPageType(render_frame())); + GetLoadingPageType(data_source)); } void NetErrorHelper::DidCommitProvisionalLoad(bool is_new_navigation,
diff --git a/chrome/renderer/net/net_error_helper.h b/chrome/renderer/net/net_error_helper.h index bc7fc80e..3e04f88 100644 --- a/chrome/renderer/net/net_error_helper.h +++ b/chrome/renderer/net/net_error_helper.h
@@ -56,7 +56,7 @@ void TrackClick(int tracking_id) override; // RenderFrameObserver implementation. - void DidStartProvisionalLoad() override; + void DidStartProvisionalLoad(blink::WebDataSource* data_source) override; void DidCommitProvisionalLoad(bool is_new_navigation, bool is_same_page_navigation) override; void DidFinishLoad() override;
diff --git a/chrome/renderer/net_benchmarking_extension.cc b/chrome/renderer/net_benchmarking_extension.cc index fa1464fd..36ff916 100644 --- a/chrome/renderer/net_benchmarking_extension.cc +++ b/chrome/renderer/net_benchmarking_extension.cc
@@ -7,7 +7,7 @@ #include "chrome/common/net_benchmarking.mojom.h" #include "content/public/renderer/render_thread.h" #include "services/service_manager/public/cpp/interface_provider.h" -#include "third_party/WebKit/public/web/WebCache.h" +#include "third_party/WebKit/public/platform/WebCache.h" #include "v8/include/v8.h" using blink::WebCache;
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index fb7b8f1..6dd43504 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1044,6 +1044,7 @@ "data/webui/settings/passwords_and_autofill_fake_data.js", "data/webui/settings/passwords_and_forms_browsertest.js", "data/webui/settings/settings_autofill_section_browsertest.js", + "data/webui/settings/settings_idle_render_browsertest.js", "data/webui/settings/settings_page_browsertest.js", "data/webui/settings/settings_passwords_section_browsertest.js", "data/webui/settings/settings_subpage_browsertest.js", @@ -1291,6 +1292,8 @@ "//ppapi/native_client:irt", ] } + + deps += [ "//chrome/browser/chromeos:test_support" ] } # TODO(jbudorick): In progress. See crbug.com/611756 @@ -1726,7 +1729,6 @@ "../browser/speech/extension_api/tts_extension_apitest.cc", "../browser/speech/speech_recognition_browsertest.cc", "../browser/spellchecker/spellcheck_service_browsertest.cc", - "../browser/ssl/captive_portal_blocking_page_browsertest.cc", "../browser/ssl/cert_verifier_browser_test.cc", "../browser/ssl/cert_verifier_browser_test.h", "../browser/ssl/certificate_reporting_test_utils.cc", @@ -2022,6 +2024,10 @@ [ "../browser/payments/site_per_process_payments_browsertest.cc" ] } + if (enable_captive_portal_detection) { + sources += + [ "../browser/ssl/captive_portal_blocking_page_browsertest.cc" ] + } if (!enable_one_click_signin) { sources -= [ "../browser/ui/sync/one_click_signin_links_delegate_impl_browsertest.cc" ] } @@ -2196,6 +2202,7 @@ "../browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc", "../browser/chromeos/app_mode/kiosk_app_update_service_browsertest.cc", "../browser/chromeos/arc/arc_session_manager_browsertest.cc", + "../browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc", "../browser/chromeos/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc", "../browser/chromeos/arc/intent_helper/arc_settings_service_browsertest.cc", "../browser/chromeos/attestation/attestation_policy_browsertest.cc", @@ -2246,12 +2253,8 @@ "../browser/chromeos/login/easy_unlock/bootstrap_browsertest.cc", "../browser/chromeos/login/enable_debugging_browsertest.cc", "../browser/chromeos/login/enrollment/enrollment_screen_browsertest.cc", - "../browser/chromeos/login/enrollment/enterprise_enrollment_helper_mock.cc", - "../browser/chromeos/login/enrollment/enterprise_enrollment_helper_mock.h", "../browser/chromeos/login/enrollment/mock_auto_enrollment_check_screen.cc", "../browser/chromeos/login/enrollment/mock_auto_enrollment_check_screen.h", - "../browser/chromeos/login/enrollment/mock_enrollment_screen.cc", - "../browser/chromeos/login/enrollment/mock_enrollment_screen.h", "../browser/chromeos/login/enterprise_enrollment_browsertest.cc", "../browser/chromeos/login/existing_user_controller_browsertest.cc", "../browser/chromeos/login/hid_detection_browsertest.cc", @@ -2271,8 +2274,6 @@ "../browser/chromeos/login/resource_loader_browsertest.cc", "../browser/chromeos/login/saml/saml_browsertest.cc", "../browser/chromeos/login/screens/hid_detection_screen_browsertest.cc", - "../browser/chromeos/login/screens/mock_base_screen_delegate.cc", - "../browser/chromeos/login/screens/mock_base_screen_delegate.h", "../browser/chromeos/login/screens/mock_enable_debugging_screen.cc", "../browser/chromeos/login/screens/mock_enable_debugging_screen.h", "../browser/chromeos/login/screens/mock_error_screen.cc", @@ -4168,7 +4169,6 @@ "../browser/ui/ash/chrome_screenshot_grabber_unittest.cc", "../browser/ui/ash/launcher/arc_app_shelf_id_unittest.cc", "../browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc", - "../browser/ui/ash/launcher/launcher_application_menu_item_model_unittest.cc", "../browser/ui/ash/launcher/launcher_context_menu_unittest.cc", "../browser/ui/ash/multi_user/multi_user_context_menu_chromeos_unittest.cc", "../browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc", @@ -5099,15 +5099,6 @@ "//chrome/common", "//mojo/edk/test:test_support", ] - - if (!is_android && use_ash) { - sources += [ - "../browser/ui/ash/launcher/test/launcher_application_menu_item_model_test_api.cc", - "../browser/ui/ash/launcher/test/launcher_application_menu_item_model_test_api.h", - "../browser/ui/ash/launcher/test/test_chrome_launcher_app_menu_item.cc", - "../browser/ui/ash/launcher/test/test_chrome_launcher_app_menu_item.h", - ] - } } if (is_android) {
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeTabUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeTabUtils.java index 9ba11cf..9b6f2bb 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeTabUtils.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeTabUtils.java
@@ -81,7 +81,11 @@ try { loadedCallback.waitForCallback(0); } catch (TimeoutException e) { - Assert.fail("Failed to load URL: " + url + ", final URL: " + tab.getUrl()); + Assert.fail("Page did not load. Tab information at time of failure --" + + " url: " + url + + ", final URL: " + tab.getUrl() + + ", load progress: " + tab.getProgress() + + ", is loading: " + Boolean.toString(tab.isLoading())); } }
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/read_file/test.js b/chrome/test/data/extensions/api_test/file_system_provider/read_file/test.js index eaf5a4d..209d807 100644 --- a/chrome/test/data/extensions/api_test/file_system_provider/read_file/test.js +++ b/chrome/test/data/extensions/api_test/file_system_provider/read_file/test.js
@@ -340,7 +340,7 @@ chrome.test.callbackPass(function(fileEntry) { fileEntry.file(chrome.test.callbackPass(function(file) { var fileReader = new FileReader(); - fileReader.onerror = chrome.test.callbackPass(function(e) { + fileReader.onabort = chrome.test.callbackPass(function(e) { chrome.test.assertEq( 'AbortError', fileReader.error.name); }); @@ -371,7 +371,7 @@ chrome.test.callbackPass(function(fileEntry) { fileEntry.file(chrome.test.callbackPass(function(file) { var fileReader = new FileReader(); - fileReader.onerror = chrome.test.callbackPass(function(e) { + fileReader.onabort = chrome.test.callbackPass(function(e) { chrome.test.assertEq( 'AbortError', fileReader.error.name); // Confirm that the file is closed on the provider side. @@ -413,7 +413,7 @@ fileEntry.file(chrome.test.callbackPass(function(file) { var fileReader = new FileReader(); var fileReader2 = new FileReader(); - fileReader.onerror = chrome.test.callbackPass(function(e) { + fileReader.onabort = chrome.test.callbackPass(function(e) { chrome.test.assertEq( 'AbortError', fileReader.error.name); // Confirm that the file is closed on the provider side.
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json index 8dda02b1..5976b4a8 100644 --- a/chrome/test/data/policy/policy_test_cases.json +++ b/chrome/test/data/policy/policy_test_cases.json
@@ -2929,6 +2929,12 @@ "DeviceLoginScreenDefaultVirtualKeyboardEnabled" : { }, + "DeviceLoginScreenLocales" : { + }, + + "DeviceLoginScreenInputMethods" : { + }, + "UptimeLimit": { },
diff --git a/chrome/test/data/webui/md_bookmarks/store_test.js b/chrome/test/data/webui/md_bookmarks/store_test.js index 9e018000..554c23a 100644 --- a/chrome/test/data/webui/md_bookmarks/store_test.js +++ b/chrome/test/data/webui/md_bookmarks/store_test.js
@@ -154,6 +154,16 @@ assertFalse(store.idToNodeMap_['3'].isSelectedFolder); }); + test('parent folder opens when descendant folder is selected', function() { + store.idToNodeMap_['0'].isOpen = false; + store.idToNodeMap_['1'].isOpen = false; + store.idToNodeMap_['3'].isOpen = false; + store.fire('selected-folder-changed', '3'); + assertTrue(store.idToNodeMap_['0'].isOpen); + assertTrue(store.idToNodeMap_['1'].isOpen); + assertFalse(store.idToNodeMap_['3'].isOpen); + }); + test('deleting a node updates the tree', function() { removeChild(TEST_TREE, 1); overrideBookmarksGetSubTree([TEST_TREE]);
diff --git a/chrome/test/data/webui/settings/advanced_page_browsertest.js b/chrome/test/data/webui/settings/advanced_page_browsertest.js index fd31d27..39b8544 100644 --- a/chrome/test/data/webui/settings/advanced_page_browsertest.js +++ b/chrome/test/data/webui/settings/advanced_page_browsertest.js
@@ -48,7 +48,7 @@ sections = sections.concat(['dateTime', 'a11y']); for (var i = 0; i < sections.length; i++) { - var section = self.getSection(page, sections[i], true /* advanced */); + var section = self.getSection(page, sections[i]); expectTrue(!!section); self.verifySubpagesHidden(section); }
diff --git a/chrome/test/data/webui/settings/device_page_tests.js b/chrome/test/data/webui/settings/device_page_tests.js index b5619b79..c953240 100644 --- a/chrome/test/data/webui/settings/device_page_tests.js +++ b/chrome/test/data/webui/settings/device_page_tests.js
@@ -33,6 +33,12 @@ cr.webUIListenerCallback('has-touchpad-changed', true); }, + /** override */ + initializeStylus: function() { + // Enable stylus. + cr.webUIListenerCallback('has-stylus-changed', true); + }, + /** @override */ handleLinkEvent: function(e) { settings.DevicePageBrowserProxyImpl.prototype.handleLinkEvent.call(
diff --git a/chrome/test/data/webui/settings/settings_idle_render_browsertest.js b/chrome/test/data/webui/settings/settings_idle_render_browsertest.js new file mode 100644 index 0000000..8f3b4213 --- /dev/null +++ b/chrome/test/data/webui/settings/settings_idle_render_browsertest.js
@@ -0,0 +1,67 @@ +// 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. + +/** @fileoverview Tests for settings-idle-render. */ + +/** @const {string} Path to root from chrome/test/data/webui/settings/. */ +var ROOT_PATH = '../../../../../'; + +/** + * @constructor + * @extends testing.Test + */ +function SettingsIdleRenderBrowserTest() {} + +SettingsIdleRenderBrowserTest.prototype = { + __proto__: testing.Test.prototype, + + /** @override */ + browsePreload: 'chrome://md-settings/controls/setting_idle_render.html', + + /** @override */ + extraLibraries: [ + ROOT_PATH + 'third_party/mocha/mocha.js', + '../mocha_adapter.js', + ], + + /** @override */ + isAsync: true, + + /** @override */ + runAccessibilityChecks: false, +}; + +TEST_F('SettingsIdleRenderBrowserTest', 'render', function() { + // Register mocha tests. + suite('Settings idle render tests', function() { + setup(function() { + var template = + '<template is="settings-idle-render" id="idleTemplate">' + + ' <div>' + + ' </div>' + + '</template>'; + document.body.innerHTML = template; + // The div should not be initially accesible. + assertFalse(!!document.body.querySelector('div')); + }); + + test('stamps after get()', function() { + // Calling get() will force stamping without waiting for idle time. + var inner = document.getElementById('idleTemplate').get(); + assertEquals('DIV', inner.nodeName); + assertEquals(inner, document.body.querySelector('div')); + }); + + test('stamps after idle', function(done) { + requestIdleCallback(function() { + // After JS calls idle-callbacks, this should be accesible. + assertTrue(!!document.body.querySelector('div')); + done(); + }); + }); + }); + + // Run all registered tests. + mocha.run(); +});
diff --git a/chrome/test/data/webui/settings/settings_main_test.js b/chrome/test/data/webui/settings/settings_main_test.js index dc271511..0e02be9 100644 --- a/chrome/test/data/webui/settings/settings_main_test.js +++ b/chrome/test/data/webui/settings/settings_main_test.js
@@ -176,7 +176,7 @@ assertEquals( expectedBasic, page.$$('#basicPage').style.display); assertEquals( - expectedAdvanced, page.$$('#advancedPage').style.display); + expectedAdvanced, page.$.advancedPageTemplate.get().style.display); } // TODO(michaelpg): It would be better not to drill into
diff --git a/chrome/test/data/webui/settings/settings_page_browsertest.js b/chrome/test/data/webui/settings/settings_page_browsertest.js index a1c5ef5..52b1fb3 100644 --- a/chrome/test/data/webui/settings/settings_page_browsertest.js +++ b/chrome/test/data/webui/settings/settings_page_browsertest.js
@@ -62,6 +62,11 @@ var pageType = 'settings-' + type + '-page'; var page = settingsMain.$$(pageType); assertTrue(!!page); + var idleRender = page.$$('template[is=settings-idle-render]'); + if (idleRender) { + idleRender.get(); + Polymer.dom.flush(); + } return page; },
diff --git a/chrome/test/media_router/media_router_e2e_browsertest.cc b/chrome/test/media_router/media_router_e2e_browsertest.cc index b9fdf39..a3b7fe6 100644 --- a/chrome/test/media_router/media_router_e2e_browsertest.cc +++ b/chrome/test/media_router/media_router_e2e_browsertest.cc
@@ -20,8 +20,7 @@ #include "content/public/test/test_utils.h" #include "media/base/test_data_util.h" #include "testing/gtest/include/gtest/gtest.h" -#include "url/gurl.h" - +#include "url/origin.h" // Use the following command to run e2e browser tests: // ./out/Debug/browser_tests --user-data-dir=<empty user data dir> @@ -42,7 +41,7 @@ const char kVideo[] = "video"; const char kBearVP9Video[] = "bear-vp9.webm"; const char kPlayer[] = "player.html"; -const char kOriginUrl[] = "http://origin/"; +const char kOrigin[] = "http://origin/"; } // namespace @@ -77,7 +76,7 @@ void MediaRouterE2EBrowserTest::CreateMediaRoute( const MediaSource& source, - const GURL& origin, + const url::Origin& origin, content::WebContents* web_contents) { DCHECK(media_router_); observer_.reset(new TestMediaSinksObserver(media_router_, source, origin)); @@ -146,8 +145,8 @@ int tab_id = SessionTabHelper::IdForTab(web_contents); // Wait for 30 seconds to make sure the route is stable. - CreateMediaRoute( - MediaSourceForTab(tab_id), GURL(kOriginUrl), web_contents); + CreateMediaRoute(MediaSourceForTab(tab_id), url::Origin(GURL(kOrigin)), + web_contents); Wait(base::TimeDelta::FromSeconds(30)); // Wait for 10 seconds to make sure route has been stopped. @@ -158,7 +157,7 @@ IN_PROC_BROWSER_TEST_F(MediaRouterE2EBrowserTest, MANUAL_CastApp) { // Wait for 30 seconds to make sure the route is stable. CreateMediaRoute(MediaSourceForPresentationUrl(GURL(kCastAppPresentationUrl)), - GURL(kOriginUrl), nullptr); + url::Origin(GURL(kOrigin)), nullptr); Wait(base::TimeDelta::FromSeconds(30)); // Wait for 10 seconds to make sure route has been stopped.
diff --git a/chrome/test/media_router/media_router_e2e_browsertest.h b/chrome/test/media_router/media_router_e2e_browsertest.h index c01681b..d051a1d 100644 --- a/chrome/test/media_router/media_router_e2e_browsertest.h +++ b/chrome/test/media_router/media_router_e2e_browsertest.h
@@ -44,7 +44,7 @@ // requesting JoinRoute() must have the same origin as the page that // requested CreateRoute()). void CreateMediaRoute(const MediaSource& source, - const GURL& origin, + const url::Origin& origin, content::WebContents* web_contents); // Stops the established media route and unregisters |observer_|.
diff --git a/chrome/test/media_router/test_media_sinks_observer.cc b/chrome/test/media_router/test_media_sinks_observer.cc index dd76964..8114a63 100644 --- a/chrome/test/media_router/test_media_sinks_observer.cc +++ b/chrome/test/media_router/test_media_sinks_observer.cc
@@ -12,7 +12,7 @@ TestMediaSinksObserver::TestMediaSinksObserver(MediaRouter* router, const MediaSource& source, - const GURL& origin) + const url::Origin& origin) : MediaSinksObserver(router, source, origin) {} TestMediaSinksObserver::~TestMediaSinksObserver() {
diff --git a/chrome/test/media_router/test_media_sinks_observer.h b/chrome/test/media_router/test_media_sinks_observer.h index 7068f2f0..f0da58a3 100644 --- a/chrome/test/media_router/test_media_sinks_observer.h +++ b/chrome/test/media_router/test_media_sinks_observer.h
@@ -21,7 +21,7 @@ public: TestMediaSinksObserver(MediaRouter* router, const MediaSource& source, - const GURL& origin); + const url::Origin& origin); ~TestMediaSinksObserver() override; // MediaSinksObserver implementation.
diff --git a/chrome/utility/safe_browsing/mac/BUILD.gn b/chrome/utility/safe_browsing/mac/BUILD.gn index d72d78b..90b9329 100644 --- a/chrome/utility/safe_browsing/mac/BUILD.gn +++ b/chrome/utility/safe_browsing/mac/BUILD.gn
@@ -69,4 +69,6 @@ ":dmg_common", "//base", ] + + libfuzzer_options = [ "close_fd_mask=2" ] }
diff --git a/chromecast/app/android/cast_jni_loader.cc b/chromecast/app/android/cast_jni_loader.cc index 6288ebb0..79a32fe 100644 --- a/chromecast/app/android/cast_jni_loader.cc +++ b/chromecast/app/android/cast_jni_loader.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/android/jni_android.h" +#include "base/android/library_loader/library_loader_hooks.h" #include "base/bind.h" #include "chromecast/android/cast_jni_registrar.h" #include "chromecast/android/platform_jni_loader.h" @@ -27,7 +28,9 @@ return true; } -bool Init() { +bool NativeInit() { + if (!content::android::OnJNIOnLoadInit()) + return false; content::Compositor::Initialize(); content::SetContentMainDelegate(new chromecast::shell::CastMainDelegate); return true; @@ -37,12 +40,10 @@ // This is called by the VM when the shared library is first loaded. JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { - std::vector<base::android::RegisterCallback> register_callbacks; - register_callbacks.push_back(base::Bind(&RegisterJNI)); - std::vector<base::android::InitCallback> init_callbacks; - init_callbacks.push_back(base::Bind(&Init)); - if (!content::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks) || - !content::android::OnJNIOnLoadInit(init_callbacks)) { + base::android::InitVM(vm); + JNIEnv* env = base::android::AttachCurrentThread(); + if (!content::android::OnJNIOnLoadRegisterJNI(env) || !RegisterJNI(env) || + !NativeInit()) { return -1; } return JNI_VERSION_1_4;
diff --git a/chromecast/app/cast_test_launcher.cc b/chromecast/app/cast_test_launcher.cc index e81e067..9a6a989 100644 --- a/chromecast/app/cast_test_launcher.cc +++ b/chromecast/app/cast_test_launcher.cc
@@ -44,7 +44,6 @@ int main(int argc, char** argv) { int default_jobs = std::max(1, base::SysInfo::NumberOfProcessors() / 2); chromecast::shell::CastTestLauncherDelegate launcher_delegate; - chromecast::RegisterPathProvider(); mojo::edk::SetMaxMessageSize(IPC::Channel::kMaximumMessageSize); mojo::edk::Init(); return content::LaunchTests(&launcher_delegate, default_jobs, argc, argv);
diff --git a/chromecast/browser/BUILD.gn b/chromecast/browser/BUILD.gn index fb4a6eec..259ef3f 100644 --- a/chromecast/browser/BUILD.gn +++ b/chromecast/browser/BUILD.gn
@@ -101,6 +101,7 @@ "//components/metrics:ui", "//components/network_hints/browser", "//components/prefs", + "//components/proxy_config", "//content", "//content/public/browser", "//content/public/common",
diff --git a/chromecast/browser/DEPS b/chromecast/browser/DEPS index 2ee51c4..ab3d80066b 100644 --- a/chromecast/browser/DEPS +++ b/chromecast/browser/DEPS
@@ -8,6 +8,7 @@ "+components/crash", "+components/network_hints/browser", "+components/prefs", + "+components/proxy_config", "+content/public/android", "+content/public/browser", "+content/public/common",
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc index 8faf8da..869ae4d 100644 --- a/chromecast/browser/cast_browser_main_parts.cc +++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -52,6 +52,7 @@ #include "chromecast/public/cast_sys_info.h" #include "chromecast/service/cast_service.h" #include "components/prefs/pref_registry_simple.h" +#include "components/proxy_config/pref_proxy_config_tracker_impl.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/gpu_data_manager.h" @@ -428,6 +429,7 @@ void CastBrowserMainParts::PreMainMessageLoopRun() { scoped_refptr<PrefRegistrySimple> pref_registry(new PrefRegistrySimple()); metrics::RegisterPrefs(pref_registry.get()); + PrefProxyConfigTrackerImpl::RegisterPrefs(pref_registry.get()); cast_browser_process_->SetPrefService( PrefServiceHelper::CreatePrefService(pref_registry.get())); @@ -437,7 +439,8 @@ cast_browser_process_->SetConnectivityChecker(ConnectivityChecker::Create( content::BrowserThread::GetTaskRunnerForThread( - content::BrowserThread::IO))); + content::BrowserThread::IO), + url_request_context_factory_->GetSystemGetter())); cast_browser_process_->SetNetLog(net_log_.get());
diff --git a/chromecast/browser/url_request_context_factory.cc b/chromecast/browser/url_request_context_factory.cc index f9119ad6..5dd6955a 100644 --- a/chromecast/browser/url_request_context_factory.cc +++ b/chromecast/browser/url_request_context_factory.cc
@@ -12,8 +12,10 @@ #include "base/memory/ptr_util.h" #include "base/threading/worker_pool.h" #include "chromecast/base/chromecast_switches.h" +#include "chromecast/browser/cast_browser_process.h" #include "chromecast/browser/cast_http_user_agent_settings.h" #include "chromecast/browser/cast_network_delegate.h" +#include "components/proxy_config/pref_proxy_config_tracker_impl.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/cookie_store_factory.h" @@ -169,6 +171,7 @@ enable_quic_(true) {} URLRequestContextFactory::~URLRequestContextFactory() { + pref_proxy_config_tracker_impl_->DetachFromPrefService(); } void URLRequestContextFactory::InitializeOnUIThread(net::NetLog* net_log) { @@ -180,12 +183,17 @@ // Proxy config service should be initialized in UI thread, since // ProxyConfigServiceDelegate on Android expects UI thread. - proxy_config_service_ = net::ProxyService::CreateSystemProxyConfigService( - content::BrowserThread::GetTaskRunnerForThread( - content::BrowserThread::IO), - content::BrowserThread::GetTaskRunnerForThread( - content::BrowserThread::FILE)); + pref_proxy_config_tracker_impl_ = + base::WrapUnique<PrefProxyConfigTrackerImpl>( + new PrefProxyConfigTrackerImpl( + CastBrowserProcess::GetInstance()->pref_service(), + content::BrowserThread::GetTaskRunnerForThread( + content::BrowserThread::IO))); + proxy_config_service_ = + pref_proxy_config_tracker_impl_->CreateTrackingProxyConfigService( + nullptr); + DCHECK(proxy_config_service_.get()); net_log_ = net_log; }
diff --git a/chromecast/browser/url_request_context_factory.h b/chromecast/browser/url_request_context_factory.h index 1b2396e..b18f31c 100644 --- a/chromecast/browser/url_request_context_factory.h +++ b/chromecast/browser/url_request_context_factory.h
@@ -5,10 +5,14 @@ #ifndef CHROMECAST_BROWSER_URL_REQUEST_CONTEXT_FACTORY_H_ #define CHROMECAST_BROWSER_URL_REQUEST_CONTEXT_FACTORY_H_ +#include <memory> + #include "content/public/browser/browser_context.h" #include "content/public/browser/content_browser_client.h" #include "net/http/http_network_session.h" +class PrefProxyConfigTracker; + namespace net { class CookieStore; class HttpTransactionFactory; @@ -124,6 +128,8 @@ bool media_dependencies_initialized_; std::unique_ptr<net::HttpTransactionFactory> media_transaction_factory_; + std::unique_ptr<PrefProxyConfigTracker> pref_proxy_config_tracker_impl_; + // Determines if QUIC is enabled for a URLContextGetter when it is created. // QUIC can be disabled at runtime by calling DisableQuic() above. // Only accessed on content::BrowserThread::IO thread.
diff --git a/chromecast/crash/cast_crashdump_uploader.cc b/chromecast/crash/cast_crashdump_uploader.cc index 5d58a07..b02eee7e 100644 --- a/chromecast/crash/cast_crashdump_uploader.cc +++ b/chromecast/crash/cast_crashdump_uploader.cc
@@ -7,6 +7,7 @@ #include <sys/stat.h> #include "base/logging.h" +#include "base/memory/ptr_util.h" // TODO(slan): Find a replacement for LibcurlWrapper in Chromium to remove the // breakpad dependency. #include "breakpad/src/common/linux/libcurl_wrapper.h" @@ -34,14 +35,14 @@ } CastCrashdumpUploader::CastCrashdumpUploader(const CastCrashdumpData& data) - : CastCrashdumpUploader(data, new google_breakpad::LibcurlWrapper()) { - // This instance of libcurlwrapper will leak. -} + : CastCrashdumpUploader( + data, + base::MakeUnique<google_breakpad::LibcurlWrapper>()) {} CastCrashdumpUploader::CastCrashdumpUploader( const CastCrashdumpData& data, - google_breakpad::LibcurlWrapper* http_layer) - : http_layer_(http_layer), data_(data) { + std::unique_ptr<google_breakpad::LibcurlWrapper> http_layer) + : http_layer_(std::move(http_layer)), data_(data) { DCHECK(http_layer_); }
diff --git a/chromecast/crash/cast_crashdump_uploader.h b/chromecast/crash/cast_crashdump_uploader.h index 29686b2..a96eaa74a 100644 --- a/chromecast/crash/cast_crashdump_uploader.h +++ b/chromecast/crash/cast_crashdump_uploader.h
@@ -6,6 +6,7 @@ #define CHROMECAST_CRASH_CAST_CRASHDUMP_UPLOADER_H_ #include <map> +#include <memory> #include <string> #include "base/macros.h" @@ -36,9 +37,9 @@ class CastCrashdumpUploader { public: - // Does not take ownership of |http_layer|. - CastCrashdumpUploader(const CastCrashdumpData& data, - google_breakpad::LibcurlWrapper* http_layer); + CastCrashdumpUploader( + const CastCrashdumpData& data, + std::unique_ptr<google_breakpad::LibcurlWrapper> http_layer); explicit CastCrashdumpUploader(const CastCrashdumpData& data); ~CastCrashdumpUploader(); @@ -50,7 +51,7 @@ private: bool CheckRequiredParametersArePresent(); - google_breakpad::LibcurlWrapper* http_layer_; + std::unique_ptr<google_breakpad::LibcurlWrapper> http_layer_; CastCrashdumpData data_; // Holds the following mapping for attachments: <label, filepath>
diff --git a/chromecast/crash/cast_crashdump_uploader_unittest.cc b/chromecast/crash/cast_crashdump_uploader_unittest.cc index b17df389..b9daa80 100644 --- a/chromecast/crash/cast_crashdump_uploader_unittest.cc +++ b/chromecast/crash/cast_crashdump_uploader_unittest.cc
@@ -5,6 +5,7 @@ #include <string> #include "base/files/file_util.h" +#include "base/memory/ptr_util.h" #include "breakpad/src/common/linux/libcurl_wrapper.h" #include "chromecast/base/scoped_temp_file.h" #include "chromecast/crash/cast_crashdump_uploader.h" @@ -35,8 +36,8 @@ using testing::Return; TEST(CastCrashdumpUploaderTest, UploadFailsWhenInitFails) { - testing::StrictMock<MockLibcurlWrapper> m; - EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(false)); + auto m = base::MakeUnique<testing::StrictMock<MockLibcurlWrapper>>(); + EXPECT_CALL(*m, Init()).Times(1).WillOnce(Return(false)); CastCrashdumpData data; data.product = "foobar"; @@ -46,20 +47,20 @@ data.comments = "none"; data.minidump_pathname = "/tmp/foo.dmp"; data.crash_server = "http://foo.com"; - CastCrashdumpUploader uploader(data, &m); + CastCrashdumpUploader uploader(data, std::move(m)); ASSERT_FALSE(uploader.Upload(nullptr)); } TEST(CastCrashdumpUploaderTest, UploadSucceedsWithValidParameters) { - testing::StrictMock<MockLibcurlWrapper> m; + auto m = base::MakeUnique<testing::StrictMock<MockLibcurlWrapper>>(); // Create a temporary file. ScopedTempFile minidump; - EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true)); - EXPECT_CALL(m, AddFile(minidump.path().value(), _)).WillOnce(Return(true)); - EXPECT_CALL(m, SendRequest("http://foo.com", _, _, _, _)).Times(1).WillOnce( + EXPECT_CALL(*m, Init()).Times(1).WillOnce(Return(true)); + EXPECT_CALL(*m, AddFile(minidump.path().value(), _)).WillOnce(Return(true)); + EXPECT_CALL(*m, SendRequest("http://foo.com", _, _, _, _)).Times(1).WillOnce( Return(true)); CastCrashdumpData data; @@ -70,15 +71,15 @@ data.comments = "none"; data.minidump_pathname = minidump.path().value(); data.crash_server = "http://foo.com"; - CastCrashdumpUploader uploader(data, &m); + CastCrashdumpUploader uploader(data, std::move(m)); ASSERT_TRUE(uploader.Upload(nullptr)); } TEST(CastCrashdumpUploaderTest, UploadFailsWithInvalidPathname) { - testing::StrictMock<MockLibcurlWrapper> m; - EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true)); - EXPECT_CALL(m, SendRequest(_, _, _, _, _)).Times(0); + auto m = base::MakeUnique<testing::StrictMock<MockLibcurlWrapper>>(); + EXPECT_CALL(*m, Init()).Times(1).WillOnce(Return(true)); + EXPECT_CALL(*m, SendRequest(_, _, _, _, _)).Times(0); CastCrashdumpData data; data.product = "foobar"; @@ -88,13 +89,12 @@ data.comments = "none"; data.minidump_pathname = "/invalid/file/path"; data.crash_server = "http://foo.com"; - CastCrashdumpUploader uploader(data, &m); + CastCrashdumpUploader uploader(data, std::move(m)); ASSERT_FALSE(uploader.Upload(nullptr)); } TEST(CastCrashdumpUploaderTest, UploadFailsWithoutAllRequiredParameters) { - testing::StrictMock<MockLibcurlWrapper> m; // Create a temporary file. ScopedTempFile minidump; @@ -111,33 +111,36 @@ // Test with empty product name. data.product = ""; - EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true)); - CastCrashdumpUploader uploader_no_product(data, &m); + auto m = base::MakeUnique<testing::StrictMock<MockLibcurlWrapper>>(); + EXPECT_CALL(*m, Init()).Times(1).WillOnce(Return(true)); + CastCrashdumpUploader uploader_no_product(data, std::move(m)); ASSERT_FALSE(uploader_no_product.Upload(nullptr)); data.product = "foobar"; // Test with empty product version. data.version = ""; - EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true)); - CastCrashdumpUploader uploader_no_version(data, &m); + m = base::MakeUnique<testing::StrictMock<MockLibcurlWrapper>>(); + EXPECT_CALL(*m, Init()).Times(1).WillOnce(Return(true)); + CastCrashdumpUploader uploader_no_version(data, std::move(m)); ASSERT_FALSE(uploader_no_version.Upload(nullptr)); data.version = "1.0"; // Test with empty client GUID. data.guid = ""; - EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true)); - CastCrashdumpUploader uploader_no_guid(data, &m); + m = base::MakeUnique<testing::StrictMock<MockLibcurlWrapper>>(); + EXPECT_CALL(*m, Init()).Times(1).WillOnce(Return(true)); + CastCrashdumpUploader uploader_no_guid(data, std::move(m)); ASSERT_FALSE(uploader_no_guid.Upload(nullptr)); } TEST(CastCrashdumpUploaderTest, UploadFailsWithInvalidAttachment) { - testing::StrictMock<MockLibcurlWrapper> m; + auto m = base::MakeUnique<testing::StrictMock<MockLibcurlWrapper>>(); // Create a temporary file. ScopedTempFile minidump; - EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true)); - EXPECT_CALL(m, AddFile(minidump.path().value(), _)).WillOnce(Return(true)); + EXPECT_CALL(*m, Init()).Times(1).WillOnce(Return(true)); + EXPECT_CALL(*m, AddFile(minidump.path().value(), _)).WillOnce(Return(true)); CastCrashdumpData data; data.product = "foobar"; @@ -147,7 +150,7 @@ data.comments = "none"; data.minidump_pathname = minidump.path().value(); data.crash_server = "http://foo.com"; - CastCrashdumpUploader uploader(data, &m); + CastCrashdumpUploader uploader(data, std::move(m)); // Add a file that does not exist as an attachment. uploader.AddAttachment("label", "/path/does/not/exist"); @@ -155,7 +158,7 @@ } TEST(CastCrashdumpUploaderTest, UploadSucceedsWithValidAttachment) { - testing::StrictMock<MockLibcurlWrapper> m; + auto m = base::MakeUnique<testing::StrictMock<MockLibcurlWrapper>>(); // Create a temporary file. ScopedTempFile minidump; @@ -163,10 +166,10 @@ // Create a valid attachment. ScopedTempFile attachment; - EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true)); - EXPECT_CALL(m, AddFile(minidump.path().value(), _)).WillOnce(Return(true)); - EXPECT_CALL(m, AddFile(attachment.path().value(), _)).WillOnce(Return(true)); - EXPECT_CALL(m, SendRequest(_, _, _, _, _)).Times(1).WillOnce(Return(true)); + EXPECT_CALL(*m, Init()).Times(1).WillOnce(Return(true)); + EXPECT_CALL(*m, AddFile(minidump.path().value(), _)).WillOnce(Return(true)); + EXPECT_CALL(*m, AddFile(attachment.path().value(), _)).WillOnce(Return(true)); + EXPECT_CALL(*m, SendRequest(_, _, _, _, _)).Times(1).WillOnce(Return(true)); CastCrashdumpData data; data.product = "foobar"; @@ -176,7 +179,7 @@ data.comments = "none"; data.minidump_pathname = minidump.path().value(); data.crash_server = "http://foo.com"; - CastCrashdumpUploader uploader(data, &m); + CastCrashdumpUploader uploader(data, std::move(m)); // Add a valid file as an attachment. uploader.AddAttachment("label", attachment.path().value());
diff --git a/chromecast/media/base/media_resource_tracker_unittest.cc b/chromecast/media/base/media_resource_tracker_unittest.cc index 3eb4524..bf10f66 100644 --- a/chromecast/media/base/media_resource_tracker_unittest.cc +++ b/chromecast/media/base/media_resource_tracker_unittest.cc
@@ -203,6 +203,9 @@ EXPECT_EQ(1u, resource_tracker_->media_use_count()); } EXPECT_EQ(0u, resource_tracker_->media_use_count()); + + resource_tracker_->FinalizeAndDestroy(); + base::RunLoop().RunUntilIdle(); } } // namespace media
diff --git a/chromecast/net/BUILD.gn b/chromecast/net/BUILD.gn index bae4aeb..224ff01 100644 --- a/chromecast/net/BUILD.gn +++ b/chromecast/net/BUILD.gn
@@ -31,6 +31,7 @@ "//chromecast/base:cast_sys_info", "//chromecast/base/metrics", "//chromecast/public", + "//components/proxy_config", "//net", ] }
diff --git a/chromecast/net/DEPS b/chromecast/net/DEPS index 8fa9d48..cd66c1f 100644 --- a/chromecast/net/DEPS +++ b/chromecast/net/DEPS
@@ -1,3 +1,4 @@ include_rules = [ "+net", + "+components/proxy_config", ]
diff --git a/chromecast/net/connectivity_checker.cc b/chromecast/net/connectivity_checker.cc index 873ab1e..9f0e7a1 100644 --- a/chromecast/net/connectivity_checker.cc +++ b/chromecast/net/connectivity_checker.cc
@@ -34,8 +34,10 @@ // static scoped_refptr<ConnectivityChecker> ConnectivityChecker::Create( - const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { - return make_scoped_refptr(new ConnectivityCheckerImpl(task_runner)); + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, + net::URLRequestContextGetter* url_request_context_getter) { + return make_scoped_refptr( + new ConnectivityCheckerImpl(task_runner, url_request_context_getter)); } } // namespace chromecast
diff --git a/chromecast/net/connectivity_checker.h b/chromecast/net/connectivity_checker.h index dff6e530..8c47710 100644 --- a/chromecast/net/connectivity_checker.h +++ b/chromecast/net/connectivity_checker.h
@@ -15,6 +15,10 @@ class SingleThreadTaskRunner; } +namespace net { +class URLRequestContextGetter; +} + namespace chromecast { // Checks if internet connectivity is available. @@ -35,7 +39,8 @@ }; static scoped_refptr<ConnectivityChecker> Create( - const scoped_refptr<base::SingleThreadTaskRunner>& task_runner); + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, + net::URLRequestContextGetter* url_request_context_getter); ConnectivityChecker();
diff --git a/chromecast/net/connectivity_checker_impl.cc b/chromecast/net/connectivity_checker_impl.cc index b1b24eb..6c1b234 100644 --- a/chromecast/net/connectivity_checker_impl.cc +++ b/chromecast/net/connectivity_checker_impl.cc
@@ -18,11 +18,10 @@ #include "net/http/http_response_headers.h" #include "net/http/http_response_info.h" #include "net/http/http_status_code.h" -#include "net/proxy/proxy_config.h" -#include "net/proxy/proxy_config_service_fixed.h" #include "net/socket/ssl_client_socket.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_builder.h" +#include "net/url_request/url_request_context_getter.h" namespace chromecast { @@ -58,7 +57,8 @@ } // namespace ConnectivityCheckerImpl::ConnectivityCheckerImpl( - const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, + net::URLRequestContextGetter* url_request_context_getter) : ConnectivityChecker(), task_runner_(task_runner), connected_(false), @@ -66,11 +66,14 @@ check_errors_(0), network_changed_pending_(false) { DCHECK(task_runner_.get()); + task_runner->PostTask(FROM_HERE, - base::Bind(&ConnectivityCheckerImpl::Initialize, this)); + base::Bind(&ConnectivityCheckerImpl::Initialize, this, + url_request_context_getter)); } -void ConnectivityCheckerImpl::Initialize() { +void ConnectivityCheckerImpl::Initialize( + net::URLRequestContextGetter* url_request_context_getter) { DCHECK(task_runner_->BelongsToCurrentThread()); base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); base::CommandLine::StringType check_url_str = @@ -78,12 +81,7 @@ connectivity_check_url_.reset(new GURL( check_url_str.empty() ? kDefaultConnectivityCheckUrl : check_url_str)); - net::URLRequestContextBuilder builder; - builder.set_proxy_config_service( - base::MakeUnique<net::ProxyConfigServiceFixed>( - net::ProxyConfig::CreateDirect())); - builder.DisableHttpCache(); - url_request_context_ = builder.Build(); + url_request_context_ = url_request_context_getter->GetURLRequestContext(); net::NetworkChangeNotifier::AddNetworkChangeObserver(this); task_runner_->PostTask(FROM_HERE, @@ -94,7 +92,6 @@ DCHECK(task_runner_.get()); net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); task_runner_->DeleteSoon(FROM_HERE, url_request_.release()); - task_runner_->DeleteSoon(FROM_HERE, url_request_context_.release()); } bool ConnectivityCheckerImpl::Connected() const { @@ -121,7 +118,7 @@ void ConnectivityCheckerImpl::CheckInternal() { DCHECK(task_runner_->BelongsToCurrentThread()); - DCHECK(url_request_context_.get()); + DCHECK(url_request_context_); // Don't check connectivity if network is offline, because Internet could be // accessible via netifs ignored.
diff --git a/chromecast/net/connectivity_checker_impl.h b/chromecast/net/connectivity_checker_impl.h index 8779d0cc..49e5e467 100644 --- a/chromecast/net/connectivity_checker_impl.h +++ b/chromecast/net/connectivity_checker_impl.h
@@ -21,6 +21,7 @@ class SSLInfo; class URLRequest; class URLRequestContext; +class URLRequestContextGetter; } namespace chromecast { @@ -34,7 +35,8 @@ public: // Connectivity checking and initialization will run on task_runner. explicit ConnectivityCheckerImpl( - const scoped_refptr<base::SingleThreadTaskRunner>& task_runner); + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, + net::URLRequestContextGetter* url_request_context_getter); // ConnectivityChecker implementation: bool Connected() const override; @@ -52,7 +54,7 @@ bool fatal) override; // Initializes ConnectivityChecker - void Initialize(); + void Initialize(net::URLRequestContextGetter* url_request_context_getter); // net::NetworkChangeNotifier::NetworkChangeObserver implementation: void OnNetworkChanged( @@ -81,7 +83,7 @@ void CheckInternal(); std::unique_ptr<GURL> connectivity_check_url_; - std::unique_ptr<net::URLRequestContext> url_request_context_; + net::URLRequestContext* url_request_context_; std::unique_ptr<net::URLRequest> url_request_; const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc index aad988d..e6dc9b5 100644 --- a/chromeos/chromeos_switches.cc +++ b/chromeos/chromeos_switches.cc
@@ -70,6 +70,8 @@ // Users can enable ARC only when Finch experiment is turned on. // - officially-supported: ARC is installed and supported on this device. So // users can enable ARC via settings etc. +// - officially-supported-with-active-directory: ARC is supported and also +// allowed to use with Active Directory management. const char kArcAvailability[] = "arc-availability"; // DEPRECATED: Please use --arc-availability=installed.
diff --git a/chromeos/dbus/auth_policy_client.cc b/chromeos/dbus/auth_policy_client.cc index ade93a7..7076ca14 100644 --- a/chromeos/dbus/auth_policy_client.cc +++ b/chromeos/dbus/auth_policy_client.cc
@@ -49,7 +49,7 @@ writer.AppendString(machine_name); writer.AppendString(user_principal_name); writer.AppendFileDescriptor(password_fd); - proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, + proxy_->CallMethod(&method_call, kSlowDbusTimeoutMilliseconds, base::Bind(&AuthPolicyClientImpl::HandleJoinCallback, weak_ptr_factory_.GetWeakPtr(), callback)); }
diff --git a/chromeos/settings/cros_settings_names.cc b/chromeos/settings/cros_settings_names.cc index dec80cf6d..f67a3777 100644 --- a/chromeos/settings/cros_settings_names.cc +++ b/chromeos/settings/cros_settings_names.cc
@@ -231,4 +231,13 @@ // format allowed to set a device-level wallpaper before any user logs in. const char kDeviceWallpaperImage[] = "cros.device_wallpaper_image"; +// A list pref specifying the locales allowed on the login screen. Currently +// only the first value is used, as the single locale allowed on the login +// screen. +const char kDeviceLoginScreenLocales[] = "cros.device_login_screen_locales"; + +// A list pref containing the input method IDs allowed on the login screen. +const char kDeviceLoginScreenInputMethods[] = + "cros.device_login_screen_input_methods"; + } // namespace chromeos
diff --git a/chromeos/settings/cros_settings_names.h b/chromeos/settings/cros_settings_names.h index c8c2ac3a..7c9c289 100644 --- a/chromeos/settings/cros_settings_names.h +++ b/chromeos/settings/cros_settings_names.h
@@ -114,6 +114,9 @@ CHROMEOS_EXPORT extern const char kDeviceWallpaperImage[]; +CHROMEOS_EXPORT extern const char kDeviceLoginScreenLocales[]; +CHROMEOS_EXPORT extern const char kDeviceLoginScreenInputMethods[]; + } // namespace chromeos #endif // CHROMEOS_SETTINGS_CROS_SETTINGS_NAMES_H_
diff --git a/chromeos/system/version_loader.h b/chromeos/system/version_loader.h index de6d2d7..db1b80e 100644 --- a/chromeos/system/version_loader.h +++ b/chromeos/system/version_loader.h
@@ -21,15 +21,15 @@ // Gets the version. // If |full_version| is true version string with extra info is extracted, // otherwise it's in short format x.x.xx.x. -// Must be run on a blocking thread pool. +// May block. CHROMEOS_EXPORT std::string GetVersion(VersionFormat format); // Gets the ARC version. -// Must be run on a blocking thread pool. +// May block. CHROMEOS_EXPORT std::string GetARCVersion(); // Gets the firmware info. -// Must be run on a blocking thread pool. +// May block. CHROMEOS_EXPORT std::string GetFirmware(); // Extracts the firmware from the file.
diff --git a/components/OWNERS b/components/OWNERS index fb6112e8a..ffa8c1d 100644 --- a/components/OWNERS +++ b/components/OWNERS
@@ -18,6 +18,7 @@ per-file password_manager_strings.grdp=file://components/password_manager/OWNERS per-file pageinfo_strings.grdp=estark@chromium.org per-file pageinfo_strings.grdp=lgarron@chromium.org +per-file payments_strings.grdp=file://components/payments/OWNERS per-file pdf_strings.grdp=raymes@chromium.org per-file pdf_strings.grdp=tsergeant@chromium.org per-file policy_strings.grdp=file://components/policy/OWNERS
diff --git a/components/arc/arc_features.h b/components/arc/arc_features.h index 52dec01..6366960 100644 --- a/components/arc/arc_features.h +++ b/components/arc/arc_features.h
@@ -4,8 +4,8 @@ // This file defines the public base::FeatureList features for ARC. -#ifndef CHROMEOS_COMPONENTS_ARC_ARC_FEATURES_H_ -#define CHROMEOS_COMPONENTS_ARC_ARC_FEATURES_H_ +#ifndef COMPONENTS_ARC_ARC_FEATURES_H_ +#define COMPONENTS_ARC_ARC_FEATURES_H_ #include "base/feature_list.h" @@ -18,4 +18,4 @@ } // namespace arc -#endif // CHROMEOS_COMPONENTS_ARC_ARC_FEATURES_H_ +#endif // COMPONENTS_ARC_ARC_FEATURES_H_
diff --git a/components/arc/arc_util.cc b/components/arc/arc_util.cc index 6e74ad0..32d9700 100644 --- a/components/arc/arc_util.cc +++ b/components/arc/arc_util.cc
@@ -25,6 +25,8 @@ constexpr char kAvailabilityNone[] = "none"; constexpr char kAvailabilityInstalled[] = "installed"; constexpr char kAvailabilityOfficiallySupported[] = "officially-supported"; +constexpr char kAvailabilityOfficiallySupportedWithActiveDirectory[] = + "officially-supported-with-active-directory"; } // namespace @@ -34,13 +36,14 @@ if (command_line->HasSwitch(chromeos::switches::kArcAvailability)) { std::string value = command_line->GetSwitchValueASCII( chromeos::switches::kArcAvailability); - DCHECK(value == kAvailabilityNone || - value == kAvailabilityInstalled || - value == kAvailabilityOfficiallySupported) + DCHECK(value == kAvailabilityNone || value == kAvailabilityInstalled || + value == kAvailabilityOfficiallySupported || + value == kAvailabilityOfficiallySupportedWithActiveDirectory) << "Unknown flag value: " << value; return value == kAvailabilityOfficiallySupported || - (value == kAvailabilityInstalled && - base::FeatureList::IsEnabled(kEnableArcFeature)); + value == kAvailabilityOfficiallySupportedWithActiveDirectory || + (value == kAvailabilityInstalled && + base::FeatureList::IsEnabled(kEnableArcFeature)); } // For transition, fallback to old flags. @@ -60,6 +63,17 @@ return user_manager::UserManager::Get()->IsLoggedInAsArcKioskApp(); } +bool IsArcAllowedForActiveDirectoryUsers() { + const auto* command_line = base::CommandLine::ForCurrentProcess(); + + if (!command_line->HasSwitch(chromeos::switches::kArcAvailability)) + return false; + + return command_line->GetSwitchValueASCII( + chromeos::switches::kArcAvailability) == + kAvailabilityOfficiallySupportedWithActiveDirectory; +} + bool IsArcOptInVerificationDisabled() { const auto* command_line = base::CommandLine::ForCurrentProcess(); return command_line->HasSwitch(
diff --git a/components/arc/arc_util.h b/components/arc/arc_util.h index 6f7ef07..30fbd3e 100644 --- a/components/arc/arc_util.h +++ b/components/arc/arc_util.h
@@ -36,6 +36,10 @@ // Returns true if ARC should run under Kiosk mode. bool IsArcKioskMode(); +// Returns true if it is allowed to use ARC with Active Directory managed +// devices. +bool IsArcAllowedForActiveDirectoryUsers(); + // Checks if opt-in verification was disabled by switch in command line. // In most cases, it is disabled for testing purpose. bool IsArcOptInVerificationDisabled();
diff --git a/components/arc/arc_util_unittest.cc b/components/arc/arc_util_unittest.cc index c7ad19f..9796e911 100644 --- a/components/arc/arc_util_unittest.cc +++ b/components/arc/arc_util_unittest.cc
@@ -5,6 +5,7 @@ #include "components/arc/arc_util.h" #include <memory> +#include <string> #include "base/command_line.h" #include "base/macros.h" @@ -113,6 +114,27 @@ EXPECT_TRUE(IsArcAvailable()); } +TEST_F(ArcUtilTest, IsArcAvailable_OfficiallySupportedWithActiveDirectory) { + // Regardless of FeatureList, IsArcAvailable() should return true. + auto* command_line = base::CommandLine::ForCurrentProcess(); + command_line->InitFromArgv( + {"", "--arc-availability=officially-supported-with-active-directory"}); + EXPECT_TRUE(IsArcAvailable()); +} + +TEST_F(ArcUtilTest, IsArcAllowedForActiveDirectoryUsers_Allowed) { + auto* command_line = base::CommandLine::ForCurrentProcess(); + command_line->InitFromArgv( + {"", "--arc-availability=officially-supported-with-active-directory"}); + EXPECT_TRUE(IsArcAllowedForActiveDirectoryUsers()); +} + +TEST_F(ArcUtilTest, IsArcAllowedForActiveDirectoryUsers_NotAllowed) { + auto* command_line = base::CommandLine::ForCurrentProcess(); + command_line->InitFromArgv({"", "--arc-availability=officially-supported"}); + EXPECT_FALSE(IsArcAllowedForActiveDirectoryUsers()); +} + // TODO(hidehiko): Add test for IsArcKioskMode(). // It depends on UserManager, but a utility to inject fake instance is // available only in chrome/. To use it in components/, refactoring is needed.
diff --git a/components/arc/bitmap/bitmap_struct_traits.h b/components/arc/bitmap/bitmap_struct_traits.h index e4e61e3..7aefb77f 100644 --- a/components/arc/bitmap/bitmap_struct_traits.h +++ b/components/arc/bitmap/bitmap_struct_traits.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENT_ARC_BITMAP_BITMAP_STRUCT_TRAITS_H_ -#define COMPONENT_ARC_BITMAP_BITMAP_STRUCT_TRAITS_H_ +#ifndef COMPONENTS_ARC_BITMAP_BITMAP_STRUCT_TRAITS_H_ +#define COMPONENTS_ARC_BITMAP_BITMAP_STRUCT_TRAITS_H_ #include "components/arc/common/bitmap.mojom.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -25,6 +25,6 @@ static bool Read(arc::mojom::ArcBitmapDataView data, SkBitmap* out); }; -} +} // namespace mojo -#endif // COMPONENT_ARC_BITMAP_BITMAP_STRUCT_TRAITS_H_ +#endif // COMPONENTS_ARC_BITMAP_BITMAP_STRUCT_TRAITS_H_
diff --git a/components/arc/bluetooth/arc_bluetooth_bridge.cc b/components/arc/bluetooth/arc_bluetooth_bridge.cc index 96c88b9..97bca58 100644 --- a/components/arc/bluetooth/arc_bluetooth_bridge.cc +++ b/components/arc/bluetooth/arc_bluetooth_bridge.cc
@@ -1069,7 +1069,13 @@ BluetoothDevice* device = bluetooth_adapter_->GetDevice(remote_addr->To<std::string>()); - DCHECK(device); + + if (!device) { + LOG(ERROR) << "Unknown device " << remote_addr->To<std::string>(); + OnGattConnectError(std::move(remote_addr), + BluetoothDevice::ConnectErrorCode::ERROR_FAILED); + return; + } if (device->IsConnected()) { bluetooth_instance->OnLEConnectionStateChange(std::move(remote_addr), true); @@ -1095,9 +1101,8 @@ BluetoothDevice* device = bluetooth_adapter_->GetDevice(remote_addr->To<std::string>()); - DCHECK(device); - if (!device->IsConnected()) { + if (!device || !device->IsConnected()) { bluetooth_instance->OnLEConnectionStateChange(std::move(remote_addr), false); return; @@ -1202,6 +1207,13 @@ BluetoothDevice* device = bluetooth_adapter_->GetDevice(remote_addr->To<std::string>()); std::vector<mojom::BluetoothGattDBElementPtr> db; + + if (!device) { + LOG(ERROR) << "Unknown device " << remote_addr->To<std::string>(); + bluetooth_instance->OnGetGattDB(std::move(remote_addr), std::move(db)); + return; + } + for (auto* service : device->GetGattServices()) { mojom::BluetoothGattDBElementPtr service_element = CreateGattDBElement( service->IsPrimary() @@ -1408,8 +1420,11 @@ const ReadRemoteRssiCallback& callback) { BluetoothDevice* device = bluetooth_adapter_->GetDevice(remote_addr->To<std::string>()); - base::Optional<int8_t> rssi = device->GetInquiryRSSI(); - callback.Run(rssi.value_or(mojom::kUnknownPower)); + if (!device) { + callback.Run(mojom::kUnknownPower); + return; + } + callback.Run(device->GetInquiryRSSI().value_or(mojom::kUnknownPower)); } void ArcBluetoothBridge::OpenBluetoothSocket( @@ -1585,6 +1600,12 @@ const BluetoothUUID& target_uuid) { BluetoothDevice* device = bluetooth_adapter_->GetDevice(remote_addr->To<std::string>()); + if (!device) { + OnGetServiceRecordsError(std::move(remote_addr), target_uuid, + bluez::BluetoothServiceRecordBlueZ::ErrorCode:: + ERROR_DEVICE_DISCONNECTED); + return; + } bluez::BluetoothDeviceBlueZ* device_bluez = static_cast<bluez::BluetoothDeviceBlueZ*>(device);
diff --git a/components/arc/bluetooth/bluetooth_struct_traits.cc b/components/arc/bluetooth/bluetooth_struct_traits.cc index 6990e4d..37d95bf 100644 --- a/components/arc/bluetooth/bluetooth_struct_traits.cc +++ b/components/arc/bluetooth/bluetooth_struct_traits.cc
@@ -5,6 +5,9 @@ #include "components/arc/bluetooth/bluetooth_struct_traits.h" #include <algorithm> +#include <map> +#include <string> +#include <utility> #include <vector> #include "base/memory/ptr_util.h"
diff --git a/components/arc/bluetooth/bluetooth_struct_traits.h b/components/arc/bluetooth/bluetooth_struct_traits.h index 2290d7a..aa60fe6 100644 --- a/components/arc/bluetooth/bluetooth_struct_traits.h +++ b/components/arc/bluetooth/bluetooth_struct_traits.h
@@ -114,19 +114,19 @@ // Dummy methods. static arc::mojom::BluetoothAdvertisementType type( - std::unique_ptr<device::BluetoothAdvertisement::Data>& input) { + const std::unique_ptr<device::BluetoothAdvertisement::Data>& input) { NOTREACHED(); return arc::mojom::BluetoothAdvertisementType::ADV_TYPE_NON_CONNECTABLE; } static bool include_tx_power( - std::unique_ptr<device::BluetoothAdvertisement::Data>& input) { + const std::unique_ptr<device::BluetoothAdvertisement::Data>& input) { NOTREACHED(); return false; } static std::vector<arc::mojom::BluetoothAdvertisingDataPtr> data( - std::unique_ptr<device::BluetoothAdvertisement::Data>& input) { + const std::unique_ptr<device::BluetoothAdvertisement::Data>& input) { NOTREACHED(); return std::vector<arc::mojom::BluetoothAdvertisingDataPtr>(); }
diff --git a/components/arc/bluetooth/bluetooth_struct_traits_unittest.cc b/components/arc/bluetooth/bluetooth_struct_traits_unittest.cc index 5c5076d7..8532e5f4 100644 --- a/components/arc/bluetooth/bluetooth_struct_traits_unittest.cc +++ b/components/arc/bluetooth/bluetooth_struct_traits_unittest.cc
@@ -25,8 +25,8 @@ constexpr uint8_t kManufacturerData[] = {0x00, 0xe0}; template <typename MojoType, typename UserType> -mojo::StructPtr<MojoType> ConvertToMojo(UserType& input) { - std::vector<uint8_t> data = MojoType::Serialize(&input); +mojo::StructPtr<MojoType> ConvertToMojo(UserType* input) { + std::vector<uint8_t> data = MojoType::Serialize(input); mojo::StructPtr<MojoType> output; MojoType::Deserialize(std::move(data), &output); return output; @@ -45,7 +45,7 @@ TEST(BluetoothStructTraitsTest, SerializeBluetoothUUID) { device::BluetoothUUID uuid_device(kUuidStr); arc::mojom::BluetoothUUIDPtr uuid_mojo = - ConvertToMojo<arc::mojom::BluetoothUUID>(uuid_device); + ConvertToMojo<arc::mojom::BluetoothUUID>(&uuid_device); EXPECT_EQ(kUuidSize, uuid_mojo->uuid.size()); for (size_t i = 0; i < kUuidSize; i++) { EXPECT_EQ(kUuidArray[i], uuid_mojo->uuid[i]); @@ -128,8 +128,7 @@ EXPECT_EQ(cic & 0xff, kManufacturerData[0]); EXPECT_EQ((cic >> 8) & 0xff, kManufacturerData[1]); EXPECT_EQ(converted_manufacturer->begin()->second.size(), - static_cast<unsigned long>(arraysize(kManufacturerData) - - sizeof(uint16_t))); + arraysize(kManufacturerData) - sizeof(uint16_t)); } TEST(BluetoothStructTraitsTest, DeserializeBluetoothAdvertisementFailure) {
diff --git a/components/arc/common/auth.mojom b/components/arc/common/auth.mojom index 8a6ba3c..b937c4df 100644 --- a/components/arc/common/auth.mojom +++ b/components/arc/common/auth.mojom
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Next MinVersion: 6 +// Next MinVersion: 7 module arc.mojom; @@ -66,7 +66,7 @@ // These values describe the type of the Chrome account to provision. [Extensible] enum ChromeAccountType { - // Next value: 3 + // Next value: 4 UNKNOWN = 0, // Chrome login account type is a user account. @@ -74,19 +74,28 @@ // Chrome login account type is a robot (service) account. ROBOT_ACCOUNT = 2, + + // Chrome login account type is an Active Directory account. + ACTIVE_DIRECTORY_ACCOUNT = 3, }; // The necessary information for Android to sign in and provision itself. struct AccountInfo { - // The authorization code that can be used in Android to sign in. If it is - // null, sign-in will be skipped. - string? auth_code; + // The authorization code that can be used in Android to sign in when + // account_type is USER_ACCOUNT or ROBOT_ACCOUNT. If it is null in these + // cases, sign-in will be skipped. + string? auth_code@0; + + // If account_type is ACTIVE_DIRECTORY_ACCOUNT, this contains an enrollment + // token for a Managed Google Play account. If it is null in this case, + // sign-in will be skipped. + [MinVersion=6] string? enrollment_token@3; // The type of Chrome account to provision. - ChromeAccountType account_type; + ChromeAccountType account_type@1; // Whether the account is managed from Chrome OS. - bool is_managed; + bool is_managed@2; }; // Next Method ID: 7.
diff --git a/components/arc/ime/arc_ime_service.cc b/components/arc/ime/arc_ime_service.cc index 2086381..c658587 100644 --- a/components/arc/ime/arc_ime_service.cc +++ b/components/arc/ime/arc_ime_service.cc
@@ -99,7 +99,7 @@ void ArcImeService::SetArcWindowDelegateForTesting( std::unique_ptr<ArcWindowDelegate> delegate) { - arc_window_delegate_= std::move(delegate); + arc_window_delegate_ = std::move(delegate); } ui::InputMethod* ArcImeService::GetInputMethod() {
diff --git a/components/arc/ime/arc_ime_service_unittest.cc b/components/arc/ime/arc_ime_service_unittest.cc index 1b2ea0e3..ad1c522 100644 --- a/components/arc/ime/arc_ime_service_unittest.cc +++ b/components/arc/ime/arc_ime_service_unittest.cc
@@ -140,7 +140,7 @@ std::unique_ptr<ArcImeService> instance_; FakeArcImeBridge* fake_arc_ime_bridge_; // Owned by |instance_| - FakeArcWindowDelegate* fake_window_delegate_; // Owned by |instance_| + FakeArcWindowDelegate* fake_window_delegate_; // Owned by |instance_| std::unique_ptr<aura::Window> arc_win_; private:
diff --git a/components/arc/intent_helper/intent_filter.cc b/components/arc/intent_helper/intent_filter.cc index 85f30b4f..e8a80455 100644 --- a/components/arc/intent_helper/intent_filter.cc +++ b/components/arc/intent_helper/intent_filter.cc
@@ -4,6 +4,8 @@ #include "components/arc/intent_helper/intent_filter.h" +#include <utility> + #include "base/compiler_specific.h" #include "base/strings/string_util.h" #include "components/arc/common/intent_helper.mojom.h"
diff --git a/components/arc/intent_helper/intent_filter_struct_traits.cc b/components/arc/intent_helper/intent_filter_struct_traits.cc index 2ef34534..e4a59fc 100644 --- a/components/arc/intent_helper/intent_filter_struct_traits.cc +++ b/components/arc/intent_helper/intent_filter_struct_traits.cc
@@ -4,6 +4,10 @@ #include "components/arc/intent_helper/intent_filter_struct_traits.h" +#include <string> +#include <utility> +#include <vector> + #include "base/strings/string_util.h" namespace mojo {
diff --git a/components/arc/intent_helper/intent_filter_struct_traits.h b/components/arc/intent_helper/intent_filter_struct_traits.h index ca9ba9c..d6cb0cf8 100644 --- a/components/arc/intent_helper/intent_filter_struct_traits.h +++ b/components/arc/intent_helper/intent_filter_struct_traits.h
@@ -2,8 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENT_ARC_INTENT_FILTER_INTENT_FILTER_STRUCT_TRAITS_H_ -#define COMPONENT_ARC_INTENT_FILTER_INTENT_FILTER_STRUCT_TRAITS_H_ +#ifndef COMPONENTS_ARC_INTENT_HELPER_INTENT_FILTER_STRUCT_TRAITS_H_ +#define COMPONENTS_ARC_INTENT_HELPER_INTENT_FILTER_STRUCT_TRAITS_H_ + +#include <string> +#include <vector> #include "components/arc/common/intent_helper.mojom.h" #include "components/arc/intent_helper/intent_filter.h" @@ -76,4 +79,4 @@ } // namespace mojo -#endif // COMPONENT_ARC_INTENT_FILTER_INTENT_FILTER_STRUCT_TRAITS_H_ +#endif // COMPONENTS_ARC_INTENT_HELPER_INTENT_FILTER_STRUCT_TRAITS_H_
diff --git a/components/arc/intent_helper/local_activity_resolver.cc b/components/arc/intent_helper/local_activity_resolver.cc index 8ea0c55..d667bff 100644 --- a/components/arc/intent_helper/local_activity_resolver.cc +++ b/components/arc/intent_helper/local_activity_resolver.cc
@@ -4,6 +4,8 @@ #include "components/arc/intent_helper/local_activity_resolver.h" +#include <utility> + #include "url/gurl.h" namespace arc {
diff --git a/components/arc/intent_helper/page_transition_util_unittest.cc b/components/arc/intent_helper/page_transition_util_unittest.cc index cc6d5d3..8c1aeb1 100644 --- a/components/arc/intent_helper/page_transition_util_unittest.cc +++ b/components/arc/intent_helper/page_transition_util_unittest.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <utility> + #include "components/arc/intent_helper/page_transition_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/page_transition_types.h"
diff --git a/components/arc/test/fake_bluetooth_instance.cc b/components/arc/test/fake_bluetooth_instance.cc index 0d8b15e..43712654 100644 --- a/components/arc/test/fake_bluetooth_instance.cc +++ b/components/arc/test/fake_bluetooth_instance.cc
@@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <utility> + #include "base/memory/ptr_util.h" #include "components/arc/test/fake_bluetooth_instance.h" -#include <utility> - namespace arc { FakeBluetoothInstance::FakeBluetoothInstance() = default;
diff --git a/components/arc/video_accelerator/video_accelerator_struct_traits.h b/components/arc/video_accelerator/video_accelerator_struct_traits.h index 68e3befd..6c76c90 100644 --- a/components/arc/video_accelerator/video_accelerator_struct_traits.h +++ b/components/arc/video_accelerator/video_accelerator_struct_traits.h
@@ -14,12 +14,12 @@ struct StructTraits<arc::mojom::ArcVideoAcceleratorDmabufPlaneDataView, arc::ArcVideoAcceleratorDmabufPlane> { static uint32_t offset(const arc::ArcVideoAcceleratorDmabufPlane& r) { - DCHECK(r.offset >= 0); + DCHECK_GE(r.offset, 0); return r.offset; } static uint32_t stride(const arc::ArcVideoAcceleratorDmabufPlane& r) { - DCHECK(r.stride >= 0); + DCHECK_GE(r.stride, 0); return r.stride; }
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc index 69a16f4..c0f4472bf 100644 --- a/components/autofill/content/renderer/password_autofill_agent.cc +++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -1167,7 +1167,8 @@ base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); } -void PasswordAutofillAgent::DidStartProvisionalLoad() { +void PasswordAutofillAgent::DidStartProvisionalLoad( + blink::WebDataSource* data_source) { std::unique_ptr<RendererSavePasswordProgressLogger> logger; if (logging_state_active_) { logger.reset(new RendererSavePasswordProgressLogger( @@ -1186,8 +1187,7 @@ // the user is performing actions outside the page (e.g. typed url, // history navigation). We don't want to trigger saving in these cases. content::DocumentState* document_state = - content::DocumentState::FromDataSource( - navigated_frame->provisionalDataSource()); + content::DocumentState::FromDataSource(data_source); content::NavigationState* navigation_state = document_state->navigation_state(); ui::PageTransition type = navigation_state->GetTransitionType();
diff --git a/components/autofill/content/renderer/password_autofill_agent.h b/components/autofill/content/renderer/password_autofill_agent.h index ce63053..0ec8f9f 100644 --- a/components/autofill/content/renderer/password_autofill_agent.h +++ b/components/autofill/content/renderer/password_autofill_agent.h
@@ -188,7 +188,7 @@ void DidFinishDocumentLoad() override; void DidFinishLoad() override; void FrameDetached() override; - void DidStartProvisionalLoad() override; + void DidStartProvisionalLoad(blink::WebDataSource* data_source) override; void WillCommitProvisionalLoad() override; void DidCommitProvisionalLoad(bool is_new_navigation, bool is_same_page_navigation) override;
diff --git a/components/autofill/core/browser/autofill_external_delegate.cc b/components/autofill/core/browser/autofill_external_delegate.cc index ff384865..e80c8ac 100644 --- a/components/autofill/core/browser/autofill_external_delegate.cc +++ b/components/autofill/core/browser/autofill_external_delegate.cc
@@ -216,7 +216,8 @@ } else if (identifier == POPUP_ITEM_ID_CLEAR_FORM) { // User selected 'Clear form'. driver_->RendererShouldClearFilledForm(); - } else if (identifier == POPUP_ITEM_ID_PASSWORD_ENTRY) { + } else if (identifier == POPUP_ITEM_ID_PASSWORD_ENTRY || + identifier == POPUP_ITEM_ID_USERNAME_ENTRY) { NOTREACHED(); // Should be handled elsewhere. } else if (identifier == POPUP_ITEM_ID_DATALIST_ENTRY) { driver_->RendererShouldAcceptDataListSuggestion(value);
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc index 72cf421..87c8d54 100644 --- a/components/autofill/core/browser/autofill_manager.cc +++ b/components/autofill/core/browser/autofill_manager.cc
@@ -309,6 +309,9 @@ if (!is_card_number_field && !is_scannable_name_on_card_field) return false; + if (IsFormNonSecure(form)) + return false; + static const int kShowScanCreditCardMaxValueLength = 6; return field.value.size() <= kShowScanCreditCardMaxValueLength; } @@ -329,6 +332,9 @@ !client_->ShouldShowSigninPromo()) return false; + if (IsFormNonSecure(form)) + return false; + // The last step is checking if we are under the limit of impressions. int impression_count = client_->GetPrefs()->GetInteger( prefs::kAutofillCreditCardSigninPromoImpressionCount); @@ -527,6 +533,11 @@ UpdateInitialInteractionTimestamp(timestamp); } +bool AutofillManager::IsFormNonSecure(const FormData& form) const { + return !client_->IsContextSecure(form.origin) || + (form.action.is_valid() && form.action.SchemeIs("http")); +} + void AutofillManager::OnQueryFormFieldAutofill(int query_id, const FormData& form, const FormFieldData& field, @@ -563,11 +574,8 @@ } std::vector<Suggestion> suggestions; - const bool is_context_secure = - !form_structure || - (client_->IsContextSecure(form_structure->source_url()) && - (!form_structure->target_url().is_valid() || - !form_structure->target_url().SchemeIs("http"))); + const bool is_context_secure = !IsFormNonSecure(form); + const bool is_http_warning_enabled = security_state::IsHttpWarningInFormEnabled();
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h index d445d38..51e6550a 100644 --- a/components/autofill/core/browser/autofill_manager.h +++ b/components/autofill/core/browser/autofill_manager.h
@@ -424,6 +424,10 @@ void UpdateInitialInteractionTimestamp( const base::TimeTicks& interaction_timestamp); + // Examines |form| and returns true if it is in a non-secure context or + // its action attribute targets a HTTP url. + bool IsFormNonSecure(const FormData& form) const; + // Uses the existing personal data in |profiles| and |credit_cards| to // determine possible field types for the |submitted_form|. This is // potentially expensive -- on the order of 50ms even for a small set of
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc index 7442b0b..219ef8e 100644 --- a/components/autofill/core/browser/autofill_manager_unittest.cc +++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -5361,6 +5361,66 @@ prefs::kAutofillCreditCardSigninPromoImpressionCount)); } +// Test that ShouldShowCreditCardSigninPromo behaves as expected for a credit +// card form on a non-secure page. +TEST_F(AutofillManagerTest, + ShouldShowCreditCardSigninPromo_CreditCardField_NonSecureContext) { + // Set up our form data. + FormData form; + CreateTestCreditCardFormData(&form, false, false); + form.origin = GURL("http://myform.com/form.html"); + form.action = GURL("https://myform.com/submit.html"); + std::vector<FormData> forms(1, form); + FormsSeen(forms); + + FormFieldData field; + test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field); + + // Both calls will now return false, regardless of the mock implementation of + // ShouldShowSigninPromo(). + EXPECT_CALL(autofill_client_, ShouldShowSigninPromo()) + .WillOnce(testing::Return(true)); + EXPECT_FALSE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field)); + + EXPECT_CALL(autofill_client_, ShouldShowSigninPromo()) + .WillOnce(testing::Return(false)); + EXPECT_FALSE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field)); + + // Number of impressions should remain at zero. + EXPECT_EQ(0, autofill_client_.GetPrefs()->GetInteger( + prefs::kAutofillCreditCardSigninPromoImpressionCount)); +} + +// Test that ShouldShowCreditCardSigninPromo behaves as expected for a credit +// card form targeting a non-secure page. +TEST_F(AutofillManagerTest, + ShouldShowCreditCardSigninPromo_CreditCardField_NonSecureAction) { + // Set up our form data. + FormData form; + CreateTestCreditCardFormData(&form, false, false); + form.origin = GURL("https://myform.com/form.html"); + form.action = GURL("http://myform.com/submit.html"); + std::vector<FormData> forms(1, form); + FormsSeen(forms); + + FormFieldData field; + test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field); + + // Both calls will now return false, regardless of the mock implementation of + // ShouldShowSigninPromo(). + EXPECT_CALL(autofill_client_, ShouldShowSigninPromo()) + .WillOnce(testing::Return(true)); + EXPECT_FALSE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field)); + + EXPECT_CALL(autofill_client_, ShouldShowSigninPromo()) + .WillOnce(testing::Return(false)); + EXPECT_FALSE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field)); + + // Number of impressions should remain at zero. + EXPECT_EQ(0, autofill_client_.GetPrefs()->GetInteger( + prefs::kAutofillCreditCardSigninPromoImpressionCount)); +} + // Test that ShouldShowCreditCardSigninPromo behaves as expected for an address // form. TEST_F(AutofillManagerTest, ShouldShowCreditCardSigninPromo_AddressField) {
diff --git a/components/autofill/core/browser/popup_item_ids.h b/components/autofill/core/browser/popup_item_ids.h index de6f51f3..7821315f 100644 --- a/components/autofill/core/browser/popup_item_ids.h +++ b/components/autofill/core/browser/popup_item_ids.h
@@ -21,6 +21,7 @@ POPUP_ITEM_ID_TITLE = -8, POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO = -9, POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE = -10, + POPUP_ITEM_ID_USERNAME_ENTRY = -11, }; } // namespace autofill
diff --git a/components/certificate_reporting/cert_logger.proto b/components/certificate_reporting/cert_logger.proto index e049841..811d918 100644 --- a/components/certificate_reporting/cert_logger.proto +++ b/components/certificate_reporting/cert_logger.proto
@@ -67,6 +67,21 @@ } optional NetworkTimeQueryingInfo network_time_querying_info = 1; + + // Records whether the Android AIA fetching feature is enabled. + // + // This is an enum rather than a boolean as a convenience to + // distinguish reports where fetching is disabled from reports that + // were sent before this field was present. (In other words, if it + // were a boolean, a value of false might mean that fetching was + // disabled, or it might mean that the browser version was older than + // when this field was added.) + enum AndroidAIAFetchingStatus { + ANDROID_AIA_FETCHING_UNKNOWN = 0; + ANDROID_AIA_FETCHING_ENABLED = 1; + ANDROID_AIA_FETCHING_DISABLED = 2; + } + optional AndroidAIAFetchingStatus android_aia_fetching_status = 2; } message CertLoggerRequest {
diff --git a/components/certificate_reporting/error_report.cc b/components/certificate_reporting/error_report.cc index 86d345f..dc3eb53c 100644 --- a/components/certificate_reporting/error_report.cc +++ b/components/certificate_reporting/error_report.cc
@@ -15,6 +15,10 @@ #include "net/cert/x509_certificate.h" #include "net/ssl/ssl_info.h" +#if defined(OS_ANDROID) +#include "net/cert/cert_verify_proc_android.h" +#endif + using network_time::NetworkTimeTracker; namespace certificate_reporting { @@ -85,6 +89,15 @@ cert_report_->set_is_issued_by_known_root(ssl_info.is_issued_by_known_root); AddCertStatusToReportErrors(ssl_info.cert_status, cert_report_.get()); + +#if defined(OS_ANDROID) + CertLoggerFeaturesInfo* features_info = cert_report_->mutable_features_info(); + features_info->set_android_aia_fetching_status( + base::FeatureList::IsEnabled( + net::CertVerifyProcAndroid::kAIAFetchingFeature) + ? CertLoggerFeaturesInfo::ANDROID_AIA_FETCHING_ENABLED + : CertLoggerFeaturesInfo::ANDROID_AIA_FETCHING_DISABLED); +#endif } ErrorReport::~ErrorReport() {}
diff --git a/components/certificate_reporting/error_report_unittest.cc b/components/certificate_reporting/error_report_unittest.cc index de6c3861..d29fb91f 100644 --- a/components/certificate_reporting/error_report_unittest.cc +++ b/components/certificate_reporting/error_report_unittest.cc
@@ -25,6 +25,11 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#if defined(OS_ANDROID) +#include "base/test/scoped_feature_list.h" +#include "net/cert/cert_verify_proc_android.h" +#endif + using net::SSLInfo; using testing::UnorderedElementsAre; using testing::UnorderedElementsAreArray; @@ -190,9 +195,9 @@ VerifyErrorReportSerialization(report_known, ssl_info, cert_errors)); } -// Tests that information about relevant features are included in the +// Tests that information about network time querying is included in the // report. -TEST(ErrorReportTest, FeatureInfo) { +TEST(ErrorReportTest, NetworkTimeQueryingFeatureInfo) { base::Thread io_thread("IO thread"); base::Thread::Options thread_options; thread_options.message_loop_type = base::MessageLoop::TYPE_IO; @@ -234,6 +239,46 @@ .network_time_query_behavior()); } +#if defined(OS_ANDROID) +// Tests that information about the Android AIA fetching feature is included in +// the report when the feature is disabled. +TEST(ErrorReportTest, AndroidAIAFetchingFeatureDisabled) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature( + net::CertVerifyProcAndroid::kAIAFetchingFeature); + + SSLInfo ssl_info; + ASSERT_NO_FATAL_FAILURE( + GetTestSSLInfo(INCLUDE_UNVERIFIED_CERT_CHAIN, &ssl_info, kCertStatus)); + ErrorReport report(kDummyHostname, ssl_info); + std::string serialized_report; + ASSERT_TRUE(report.Serialize(&serialized_report)); + CertLoggerRequest parsed; + ASSERT_TRUE(parsed.ParseFromString(serialized_report)); + EXPECT_EQ(CertLoggerFeaturesInfo::ANDROID_AIA_FETCHING_DISABLED, + parsed.features_info().android_aia_fetching_status()); +} + +// Tests that information about the Android AIA fetching feature is included in +// the report when the feature is enabled. +TEST(ErrorReportTest, AndroidAIAFetchingFeatureEnabled) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + net::CertVerifyProcAndroid::kAIAFetchingFeature); + + SSLInfo ssl_info; + ASSERT_NO_FATAL_FAILURE( + GetTestSSLInfo(INCLUDE_UNVERIFIED_CERT_CHAIN, &ssl_info, kCertStatus)); + ErrorReport report(kDummyHostname, ssl_info); + std::string serialized_report; + ASSERT_TRUE(report.Serialize(&serialized_report)); + CertLoggerRequest parsed; + ASSERT_TRUE(parsed.ParseFromString(serialized_report)); + EXPECT_EQ(CertLoggerFeaturesInfo::ANDROID_AIA_FETCHING_ENABLED, + parsed.features_info().android_aia_fetching_status()); +} +#endif + } // namespace } // namespace certificate_reporting
diff --git a/components/components_strings.grd b/components/components_strings.grd index 35ebafa..9e112517 100644 --- a/components/components_strings.grd +++ b/components/components_strings.grd
@@ -202,6 +202,7 @@ <part file="omnibox_strings.grdp" /> <part file="pageinfo_strings.grdp" /> <part file="password_manager_strings.grdp" /> + <part file="payments_strings.grdp" /> <part file="pdf_strings.grdp" /> <part file="physical_web_ui_strings.grdp" /> <part file="policy_strings.grdp" />
diff --git a/components/content_settings/core/browser/content_settings_registry.cc b/components/content_settings/core/browser/content_settings_registry.cc index 917c6cc..2eff2da 100644 --- a/components/content_settings/core/browser/content_settings_registry.cc +++ b/components/content_settings/core/browser/content_settings_registry.cc
@@ -273,6 +273,15 @@ WebsiteSettingsRegistry::PLATFORM_ANDROID, ContentSettingsInfo::INHERIT_IF_LESS_PERMISSIVE); + Register(CONTENT_SETTINGS_TYPE_SUBRESOURCE_FILTER, "subresource-filter", + CONTENT_SETTING_ALLOW, + WebsiteSettingsInfo::UNSYNCABLE, WhitelistedSchemes(), + ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK), + WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE, + WebsiteSettingsRegistry::DESKTOP | + WebsiteSettingsRegistry::PLATFORM_ANDROID, + ContentSettingsInfo::INHERIT_IF_LESS_PERMISSIVE); + // Content settings that aren't used to store any data. TODO(raymes): use a // different mechanism rather than content settings to represent these. // Since nothing is stored in them, there is no real point in them being a
diff --git a/components/content_settings/core/common/content_settings.cc b/components/content_settings/core/common/content_settings.cc index 5161c59..ec16215 100644 --- a/components/content_settings/core/common/content_settings.cc +++ b/components/content_settings/core/common/content_settings.cc
@@ -58,7 +58,9 @@ CONTENT_SETTINGS_TYPE_AUTOPLAY, CONTENT_SETTINGS_TYPE_DEFAULT, // PROMPT_NO_DECISION_COUNT (migrated). CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, - CONTENT_SETTINGS_TYPE_PERMISSION_AUTOBLOCKER_DATA}; + CONTENT_SETTINGS_TYPE_PERMISSION_AUTOBLOCKER_DATA, + CONTENT_SETTINGS_TYPE_SUBRESOURCE_FILTER, +}; int ContentSettingTypeToHistogramValue(ContentSettingsType content_setting, size_t* num_values) {
diff --git a/components/content_settings/core/common/content_settings_types.h b/components/content_settings/core/common/content_settings_types.h index e893576..dd251805 100644 --- a/components/content_settings/core/common/content_settings_types.h +++ b/components/content_settings/core/common/content_settings_types.h
@@ -46,6 +46,7 @@ CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT, CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, CONTENT_SETTINGS_TYPE_PERMISSION_AUTOBLOCKER_DATA, + CONTENT_SETTINGS_TYPE_SUBRESOURCE_FILTER, // WARNING: This enum is going to be removed soon. Do not depend on NUM_TYPES. CONTENT_SETTINGS_NUM_TYPES_DO_NOT_USE,
diff --git a/components/contextual_search/renderer/overlay_js_render_frame_observer.cc b/components/contextual_search/renderer/overlay_js_render_frame_observer.cc index ae39705..d5a2b7f8 100644 --- a/components/contextual_search/renderer/overlay_js_render_frame_observer.cc +++ b/components/contextual_search/renderer/overlay_js_render_frame_observer.cc
@@ -25,7 +25,8 @@ OverlayJsRenderFrameObserver::~OverlayJsRenderFrameObserver() {} -void OverlayJsRenderFrameObserver::DidStartProvisionalLoad() { +void OverlayJsRenderFrameObserver::DidStartProvisionalLoad( + blink::WebDataSource* data_source) { RegisterMojoInterface(); }
diff --git a/components/contextual_search/renderer/overlay_js_render_frame_observer.h b/components/contextual_search/renderer/overlay_js_render_frame_observer.h index 595cea3..53a7c87 100644 --- a/components/contextual_search/renderer/overlay_js_render_frame_observer.h +++ b/components/contextual_search/renderer/overlay_js_render_frame_observer.h
@@ -25,7 +25,7 @@ ~OverlayJsRenderFrameObserver() override; // RenderFrameObserver implementation. - void DidStartProvisionalLoad() override; + void DidStartProvisionalLoad(blink::WebDataSource* data_source) override; void DidClearWindowObject() override; void DidFinishLoad() override;
diff --git a/components/crash/content/app/breakpad_linux.cc b/components/crash/content/app/breakpad_linux.cc index 6e5058e..b621143 100644 --- a/components/crash/content/app/breakpad_linux.cc +++ b/components/crash/content/app/breakpad_linux.cc
@@ -100,6 +100,7 @@ #if defined(ADDRESS_SANITIZER) const char* g_asan_report_str = nullptr; #endif + #if defined(OS_ANDROID) #define G_DUMPS_SUPPRESSED_MAGIC 0x5AFECEDE uint32_t g_dumps_suppressed = 0; @@ -1157,16 +1158,41 @@ LoadDataFromFD(allocator, *fd, true, file_data, size); } +// Concatenates a |prefix| and a |number| to get a string like "--foo=123" or +// "/dev/fd/4". Safe to run in a compromised context. The returned memory is +// internally owned by |allocator|. +char* StringFromPrefixAndUint(const char* prefix, + uint64_t number, + google_breakpad::PageAllocator* allocator) { + // Convert the number to a string. + char number_buf[kUint64StringSize]; + const unsigned number_len = my_uint64_len(number); + my_uint64tos(number_buf, number, number_len); + number_buf[number_len] = '\0'; + + // Concatenate the prefix and number. + size_t output_len = my_strlen(prefix) + my_strlen(number_buf) + 1; + char* output = reinterpret_cast<char*>(allocator->Alloc(output_len)); + my_strlcpy(output, prefix, output_len); + my_strlcat(output, number_buf, output_len); + return output; +} + // Spawn the appropriate upload process for the current OS: // - generic Linux invokes wget. -// - ChromeOS invokes crash_reporter. +// - Chrome OS invokes crash_reporter. Crashes are uploaded by a separate +// crash_sender script that runs periodically. // |dumpfile| is the path to the dump data file. // |mime_boundary| is only used on Linux. // |exe_buf| is only used on CrOS and is the crashing process' name. +// |upload_status_fd| is the file descriptor of a pipe that will receive: +// - On Linux, the crash report id +// - On Chrome OS, the magic crash complete string. void ExecUploadProcessOrTerminate(const BreakpadInfo& info, const char* dumpfile, const char* mime_boundary, const char* exe_buf, + int upload_status_fd, google_breakpad::PageAllocator* allocator) { #if defined(OS_CHROMEOS) // CrOS uses crash_reporter instead of wget to report crashes, @@ -1174,16 +1200,13 @@ // crashing process. static const char kCrashReporterBinary[] = "/sbin/crash_reporter"; - char pid_buf[kUint64StringSize]; - uint64_t pid_str_length = my_uint64_len(info.pid); - my_uint64tos(pid_buf, info.pid, pid_str_length); - pid_buf[pid_str_length] = '\0'; - - char uid_buf[kUint64StringSize]; - uid_t uid = geteuid(); - uint64_t uid_str_length = my_uint64_len(uid); - my_uint64tos(uid_buf, uid, uid_str_length); - uid_buf[uid_str_length] = '\0'; + // crash_reporter writes output to stdout. Connect it to the status pipe fd. + if (sys_dup2(upload_status_fd, STDOUT_FILENO) == -1) { + const char err[] = "dup2 failed\n"; + WriteLog(err, sizeof(err) - 1); + // Continue anyway, as crash_report may succeed even if we can't read its + // status. + } const char kChromeFlag[] = "--chrome="; size_t buf_len = my_strlen(dumpfile) + sizeof(kChromeFlag); @@ -1192,19 +1215,8 @@ my_strlcat(chrome_flag, kChromeFlag, buf_len); my_strlcat(chrome_flag, dumpfile, buf_len); - const char kPidFlag[] = "--pid="; - buf_len = my_strlen(pid_buf) + sizeof(kPidFlag); - char* pid_flag = reinterpret_cast<char*>(allocator->Alloc(buf_len)); - pid_flag[0] = '\0'; - my_strlcat(pid_flag, kPidFlag, buf_len); - my_strlcat(pid_flag, pid_buf, buf_len); - - const char kUidFlag[] = "--uid="; - buf_len = my_strlen(uid_buf) + sizeof(kUidFlag); - char* uid_flag = reinterpret_cast<char*>(allocator->Alloc(buf_len)); - uid_flag[0] = '\0'; - my_strlcat(uid_flag, kUidFlag, buf_len); - my_strlcat(uid_flag, uid_buf, buf_len); + char* pid_flag = StringFromPrefixAndUint("--pid=", info.pid, allocator); + char* uid_flag = StringFromPrefixAndUint("--uid=", geteuid(), allocator); const char kExeBuf[] = "--exe="; buf_len = my_strlen(exe_buf) + sizeof(kExeBuf); @@ -1223,7 +1235,9 @@ }; static const char msg[] = "Cannot upload crash dump: cannot exec " "/sbin/crash_reporter\n"; -#else + +#else // defined(OS_CHROMEOS) + // Compress |dumpfile| with gzip. const pid_t gzip_child = sys_fork(); if (gzip_child < 0) { @@ -1293,6 +1307,10 @@ my_strlcpy(post_file, post_file_msg, post_file_size); my_strlcat(post_file, dumpfile, post_file_size); + // Write the wget status output to the status pipe file descriptor path. + char* status_fd_path = + StringFromPrefixAndUint("/dev/fd/", upload_status_fd, allocator); + static const char kWgetBinary[] = "/usr/bin/wget"; const char* args[] = { kWgetBinary, @@ -1302,13 +1320,14 @@ kUploadURL, "--timeout=10", // Set a timeout so we don't hang forever. "--tries=1", // Don't retry if the upload fails. - "-O", // output reply to fd 3 - "/dev/fd/3", + "-O", // Output reply to the file descriptor path. + status_fd_path, nullptr, }; static const char msg[] = "Cannot upload crash dump: cannot exec " "/usr/bin/wget\n"; -#endif +#endif // defined(OS_CHROMEOS) + execve(args[0], const_cast<char**>(args), environ); WriteLog(msg, sizeof(msg) - 1); sys__exit(1); @@ -1352,9 +1371,13 @@ // |buf| should be |expected_len| + 1 characters in size and nullptr terminated. bool IsValidCrashReportId(const char* buf, size_t bytes_read, size_t expected_len) { - if (bytes_read != expected_len) + if (bytes_read != expected_len) { + static const char msg[] = "Unexpected crash report id length\n"; + WriteLog(msg, sizeof(msg) - 1); return false; + } #if defined(OS_CHROMEOS) + // See kSuccessMagic in platform2/crash-reporter/chrome_collector.cc. return my_strcmp(buf, "_sys_cr_finished") == 0; #else for (size_t i = 0; i < bytes_read; ++i) { @@ -1372,7 +1395,7 @@ if (!IsValidCrashReportId(buf, bytes_read, expected_len)) { #if defined(OS_CHROMEOS) static const char msg[] = - "System crash-reporter failed to process crash report."; + "System crash_reporter failed to process crash report."; #else static const char msg[] = "Failed to get crash dump id."; #endif @@ -1447,6 +1470,27 @@ } #endif +// Attempts to close all open file descriptors other than stdin, stdout and +// stderr (0, 1, and 2). +void CloseAllFileDescriptors() { + const int fd = sys_open("/proc/self/fd", O_DIRECTORY | O_RDONLY, 0); + if (fd < 0) { + for (unsigned i = 3; i < 8192; ++i) + IGNORE_RET(sys_close(i)); + } else { + google_breakpad::DirectoryReader reader(fd); + const char* name; + while (reader.GetNextEntry(&name)) { + int i; + if (my_strtoui(&i, name) && i > 2 && i != fd) + IGNORE_RET(sys_close(i)); + reader.PopEntry(); + } + + IGNORE_RET(sys_close(fd)); + } +} + void HandleCrashDump(const BreakpadInfo& info) { int dumpfd; bool keep_fd = false; @@ -1779,22 +1823,7 @@ // hold them open for too long. // // Thus, we have to loop and try and close everything. - const int fd = sys_open("/proc/self/fd", O_DIRECTORY | O_RDONLY, 0); - if (fd < 0) { - for (unsigned i = 3; i < 8192; ++i) - IGNORE_RET(sys_close(i)); - } else { - google_breakpad::DirectoryReader reader(fd); - const char* name; - while (reader.GetNextEntry(&name)) { - int i; - if (my_strtoui(&i, name) && i > 2 && i != fd) - IGNORE_RET(sys_close(i)); - reader.PopEntry(); - } - - IGNORE_RET(sys_close(fd)); - } + CloseAllFileDescriptors(); IGNORE_RET(sys_setsid()); @@ -1805,15 +1834,15 @@ const pid_t upload_child = sys_fork(); if (!upload_child) { // Upload process. - IGNORE_RET(sys_close(fds[0])); - IGNORE_RET(sys_dup2(fds[1], 3)); + IGNORE_RET(sys_close(fds[0])); // Close read end of pipe. + // Write status to the pipe. ExecUploadProcessOrTerminate(info, temp_file, mime_boundary, exe_buf, - &allocator); + fds[1], &allocator); } // Helper process. if (upload_child > 0) { - IGNORE_RET(sys_close(fds[1])); + IGNORE_RET(sys_close(fds[1])); // Close write end of pipe. const size_t kCrashIdLength = 16; char id_buf[kCrashIdLength + 1];
diff --git a/components/cronet/android/cronet_library_loader.cc b/components/cronet/android/cronet_library_loader.cc index 607df9c..6d4d117 100644 --- a/components/cronet/android/cronet_library_loader.cc +++ b/components/cronet/android/cronet_library_loader.cc
@@ -63,7 +63,9 @@ env, kCronetRegisteredMethods, arraysize(kCronetRegisteredMethods)); } -bool Init() { +bool NativeInit() { + if (!base::android::OnJNIOnLoadInit()) + return false; url::Initialize(); return true; } @@ -72,12 +74,10 @@ // Checks the available version of JNI. Also, caches Java reflection artifacts. jint CronetOnLoad(JavaVM* vm, void* reserved) { - std::vector<base::android::RegisterCallback> register_callbacks; - register_callbacks.push_back(base::Bind(&RegisterJNI)); - std::vector<base::android::InitCallback> init_callbacks; - init_callbacks.push_back(base::Bind(&Init)); - if (!base::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks) || - !base::android::OnJNIOnLoadInit(init_callbacks)) { + base::android::InitVM(vm); + JNIEnv* env = base::android::AttachCurrentThread(); + if (!base::android::OnJNIOnLoadRegisterJNI(env) || !RegisterJNI(env) || + !NativeInit()) { return -1; } return JNI_VERSION_1_6;
diff --git a/components/cronet/android/test/cronet_test_jni.cc b/components/cronet/android/test/cronet_test_jni.cc index 972da50..d278afe 100644 --- a/components/cronet/android/test/cronet_test_jni.cc +++ b/components/cronet/android/test/cronet_test_jni.cc
@@ -41,15 +41,10 @@ // This is called by the VM when the shared library is first loaded. // Checks the available version of JNI. Also, caches Java reflection artifacts. extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) { - JNIEnv* env; - if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { - return -1; - } - - std::vector<base::android::RegisterCallback> register_callbacks; - std::vector<base::android::InitCallback> init_callbacks; - if (!base::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks) || - !base::android::OnJNIOnLoadInit(init_callbacks)) { + base::android::InitVM(vm); + JNIEnv* env = base::android::AttachCurrentThread(); + if (!base::android::OnJNIOnLoadRegisterJNI(env) || + !base::android::OnJNIOnLoadInit()) { return -1; } @@ -65,4 +60,3 @@ extern "C" void JNI_OnUnLoad(JavaVM* vm, void* reserved) { base::android::LibraryLoaderExitHook(); } -
diff --git a/components/data_reduction_proxy/content/browser/content_resource_type_provider_unittest.cc b/components/data_reduction_proxy/content/browser/content_resource_type_provider_unittest.cc index 503f0c3..099aab5 100644 --- a/components/data_reduction_proxy/content/browser/content_resource_type_provider_unittest.cc +++ b/components/data_reduction_proxy/content/browser/content_resource_type_provider_unittest.cc
@@ -18,6 +18,7 @@ #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h" #include "content/public/browser/resource_request_info.h" #include "content/public/common/previews_state.h" +#include "net/socket/socket_test_util.h" #include "net/url_request/url_request.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_test_util.h" @@ -51,15 +52,21 @@ const Client kClient = Client::UNKNOWN; #endif +const std::string kBody = "response body"; + } // namespace class ContentResourceProviderTest : public testing::Test { public: ContentResourceProviderTest() - : context_(true), content_resource_type_provider_(nullptr) { + : context_(true), content_resource_type_provider_(nullptr) {} + + void Init(const std::vector<DataReductionProxyServer> proxy_servers) { test_context_ = DataReductionProxyTestContext::Builder() .WithClient(kClient) + .WithProxiesForHttp(proxy_servers) .WithURLRequestContext(&context_) + .WithMockClientSocketFactory(&mock_socket_factory_) .Build(); data_reduction_proxy_network_delegate_.reset( @@ -73,10 +80,13 @@ data_reduction_proxy_network_delegate_->InitIODataAndUMA( test_context_->io_data(), test_context_->io_data()->bypass_stats()); + context_.set_client_socket_factory(&mock_socket_factory_); context_.set_network_delegate(data_reduction_proxy_network_delegate_.get()); context_.set_proxy_delegate(test_context_->io_data()->proxy_delegate()); context_.Init(); + test_context_->EnableDataReductionProxyWithSecureProxyCheckSuccess(); + std::unique_ptr<data_reduction_proxy::ContentResourceTypeProvider> content_resource_type_provider( new data_reduction_proxy::ContentResourceTypeProvider()); @@ -109,9 +119,14 @@ return content_resource_type_provider_; } + net::MockClientSocketFactory* mock_socket_factory() { + return &mock_socket_factory_; + } + protected: base::MessageLoopForIO message_loop_; net::TestURLRequestContext context_; + net::MockClientSocketFactory mock_socket_factory_; net::TestDelegate delegate_; std::unique_ptr<DataReductionProxyTestContext> test_context_; std::unique_ptr<DataReductionProxyNetworkDelegate> @@ -119,9 +134,22 @@ ResourceTypeProvider* content_resource_type_provider_; }; -// Tests that the resource content type was correctly computed, and was -// available to the data reduction proxy delegate. -TEST_F(ContentResourceProviderTest, SetAndGetContentResourceType) { +// Tests that the correct data reduction proxy is used based on the resource +// content type. +TEST_F(ContentResourceProviderTest, VerifyCorrectProxyUsed) { + std::vector<DataReductionProxyServer> proxies_for_http; + + net::ProxyServer core_primary = net::ProxyServer::FromURI( + "http://origin.net:80", net::ProxyServer::SCHEME_HTTP); + net::ProxyServer core_fallback = net::ProxyServer::FromURI( + "http://fallback.net:80", net::ProxyServer::SCHEME_HTTP); + + proxies_for_http.push_back( + DataReductionProxyServer(core_primary, ProxyServer_ProxyType_CORE)); + proxies_for_http.push_back( + DataReductionProxyServer(core_fallback, ProxyServer_ProxyType_CORE)); + Init(proxies_for_http); + const struct { GURL gurl; content::ResourceType resource_type; @@ -156,6 +184,15 @@ ResourceTypeProvider::CONTENT_TYPE_UNKNOWN}}; for (const auto test : tests) { + net::MockRead mock_reads[] = { + net::MockRead( + "HTTP/1.1 200 OK\r\nVia: 1.1 Chrome-Compression-Proxy\r\n\r\n"), + net::MockRead(kBody.c_str()), net::MockRead(net::SYNCHRONOUS, net::OK), + }; + net::StaticSocketDataProvider socket_data_provider( + mock_reads, arraysize(mock_reads), nullptr, 0); + mock_socket_factory()->AddSocketDataProvider(&socket_data_provider); + base::HistogramTester histogram_tester; std::unique_ptr<net::URLRequest> request = CreateRequestByType(test.gurl, test.resource_type); @@ -173,6 +210,180 @@ // give the correct result. EXPECT_EQ(test.expected_content_type, content_resource_type_provider()->GetContentType(request->url())); + + EXPECT_EQ(core_primary, request->proxy_server()); + } +} + +// Tests that the resource content type was correctly computed, and was +// available to the data reduction proxy delegate. +TEST_F(ContentResourceProviderTest, SetAndGetContentResourceTypeContent) { + std::vector<DataReductionProxyServer> proxies_for_http; + + net::ProxyServer unspecified = net::ProxyServer::FromURI( + "http://origin.net:80", net::ProxyServer::SCHEME_HTTP); + net::ProxyServer core = net::ProxyServer::FromURI( + "http://fallback.net:80", net::ProxyServer::SCHEME_HTTP); + + proxies_for_http.push_back(DataReductionProxyServer( + unspecified, ProxyServer_ProxyType_UNSPECIFIED_TYPE)); + proxies_for_http.push_back( + DataReductionProxyServer(core, ProxyServer_ProxyType_CORE)); + Init(proxies_for_http); + + const struct { + GURL gurl; + content::ResourceType resource_type; + ResourceTypeProvider::ContentType expected_content_type; + } tests[] = { + {GURL("http://www.google.com/main-frame"), + content::RESOURCE_TYPE_MAIN_FRAME, + ResourceTypeProvider::CONTENT_TYPE_UNKNOWN}, + {GURL("http://www.google.com/sub-frame"), + content::RESOURCE_TYPE_SUB_FRAME, + ResourceTypeProvider::CONTENT_TYPE_UNKNOWN}, + {GURL("http://www.google.com/stylesheet"), + content::RESOURCE_TYPE_STYLESHEET, + ResourceTypeProvider::CONTENT_TYPE_UNKNOWN}, + {GURL("http://www.google.com/script"), content::RESOURCE_TYPE_SCRIPT, + ResourceTypeProvider::CONTENT_TYPE_UNKNOWN}, + {GURL("http://www.google.com/image"), content::RESOURCE_TYPE_IMAGE, + ResourceTypeProvider::CONTENT_TYPE_UNKNOWN}, + {GURL("http://www.google.com/font"), content::RESOURCE_TYPE_FONT_RESOURCE, + ResourceTypeProvider::CONTENT_TYPE_UNKNOWN}, + {GURL("http://www.google.com/sub-resource"), + content::RESOURCE_TYPE_SUB_RESOURCE, + ResourceTypeProvider::CONTENT_TYPE_UNKNOWN}, + {GURL("http://www.google.com/object"), content::RESOURCE_TYPE_OBJECT, + ResourceTypeProvider::CONTENT_TYPE_UNKNOWN}, + {GURL("http://www.google.com/media"), content::RESOURCE_TYPE_MEDIA, + ResourceTypeProvider::CONTENT_TYPE_MEDIA}, + {GURL("http://www.google.com/worker"), content::RESOURCE_TYPE_WORKER, + ResourceTypeProvider::CONTENT_TYPE_UNKNOWN}, + {GURL("http://www.google.com/shared-worker"), + content::RESOURCE_TYPE_SHARED_WORKER, + ResourceTypeProvider::CONTENT_TYPE_UNKNOWN}}; + + for (const auto test : tests) { + net::MockRead mock_reads[] = { + net::MockRead( + "HTTP/1.1 200 OK\r\nVia: 1.1 Chrome-Compression-Proxy\r\n\r\n"), + net::MockRead(kBody.c_str()), net::MockRead(net::SYNCHRONOUS, net::OK), + }; + net::StaticSocketDataProvider socket_data_provider( + mock_reads, arraysize(mock_reads), nullptr, 0); + mock_socket_factory()->AddSocketDataProvider(&socket_data_provider); + + base::HistogramTester histogram_tester; + std::unique_ptr<net::URLRequest> request = + CreateRequestByType(test.gurl, test.resource_type); + request->Start(); + base::RunLoop().RunUntilIdle(); + + histogram_tester.ExpectUniqueSample( + "DataReductionProxy.ResourceContentType", test.expected_content_type, + 1); + + EXPECT_EQ(test.expected_content_type, + content_resource_type_provider()->GetContentType(request->url())); + + // Querying for the content type of |request->url()| again should still + // give the correct result. + EXPECT_EQ(test.expected_content_type, + content_resource_type_provider()->GetContentType(request->url())); + + if (test.expected_content_type == + ResourceTypeProvider::CONTENT_TYPE_MEDIA) { + EXPECT_EQ(core, request->proxy_server()); + } else { + EXPECT_EQ(unspecified, request->proxy_server()); + } + } +} + +// Tests that the request is fetched directly if no valid data reduction +// proxy is available. +TEST_F(ContentResourceProviderTest, FetchDirect) { + std::vector<DataReductionProxyServer> proxies_for_http; + + net::ProxyServer unspecified = net::ProxyServer::FromURI( + "http://origin.net:80", net::ProxyServer::SCHEME_HTTP); + net::ProxyServer core = net::ProxyServer::FromURI( + "http://fallback.net:80", net::ProxyServer::SCHEME_HTTP); + + proxies_for_http.push_back(DataReductionProxyServer( + unspecified, ProxyServer_ProxyType_UNSPECIFIED_TYPE)); + proxies_for_http.push_back( + DataReductionProxyServer(core, ProxyServer_ProxyType_UNSPECIFIED_TYPE)); + Init(proxies_for_http); + + const struct { + GURL gurl; + content::ResourceType resource_type; + ResourceTypeProvider::ContentType expected_content_type; + } tests[] = { + {GURL("http://www.google.com/main-frame"), + content::RESOURCE_TYPE_MAIN_FRAME, + ResourceTypeProvider::CONTENT_TYPE_UNKNOWN}, + {GURL("http://www.google.com/sub-frame"), + content::RESOURCE_TYPE_SUB_FRAME, + ResourceTypeProvider::CONTENT_TYPE_UNKNOWN}, + {GURL("http://www.google.com/stylesheet"), + content::RESOURCE_TYPE_STYLESHEET, + ResourceTypeProvider::CONTENT_TYPE_UNKNOWN}, + {GURL("http://www.google.com/script"), content::RESOURCE_TYPE_SCRIPT, + ResourceTypeProvider::CONTENT_TYPE_UNKNOWN}, + {GURL("http://www.google.com/image"), content::RESOURCE_TYPE_IMAGE, + ResourceTypeProvider::CONTENT_TYPE_UNKNOWN}, + {GURL("http://www.google.com/font"), content::RESOURCE_TYPE_FONT_RESOURCE, + ResourceTypeProvider::CONTENT_TYPE_UNKNOWN}, + {GURL("http://www.google.com/sub-resource"), + content::RESOURCE_TYPE_SUB_RESOURCE, + ResourceTypeProvider::CONTENT_TYPE_UNKNOWN}, + {GURL("http://www.google.com/object"), content::RESOURCE_TYPE_OBJECT, + ResourceTypeProvider::CONTENT_TYPE_UNKNOWN}, + {GURL("http://www.google.com/media"), content::RESOURCE_TYPE_MEDIA, + ResourceTypeProvider::CONTENT_TYPE_MEDIA}, + {GURL("http://www.google.com/worker"), content::RESOURCE_TYPE_WORKER, + ResourceTypeProvider::CONTENT_TYPE_UNKNOWN}, + {GURL("http://www.google.com/shared-worker"), + content::RESOURCE_TYPE_SHARED_WORKER, + ResourceTypeProvider::CONTENT_TYPE_UNKNOWN}}; + + for (const auto test : tests) { + net::MockRead mock_reads[] = { + net::MockRead( + "HTTP/1.1 200 OK\r\nVia: 1.1 Chrome-Compression-Proxy\r\n\r\n"), + net::MockRead(kBody.c_str()), net::MockRead(net::SYNCHRONOUS, net::OK), + }; + net::StaticSocketDataProvider socket_data_provider( + mock_reads, arraysize(mock_reads), nullptr, 0); + mock_socket_factory()->AddSocketDataProvider(&socket_data_provider); + + base::HistogramTester histogram_tester; + std::unique_ptr<net::URLRequest> request = + CreateRequestByType(test.gurl, test.resource_type); + request->Start(); + base::RunLoop().RunUntilIdle(); + + histogram_tester.ExpectUniqueSample( + "DataReductionProxy.ResourceContentType", test.expected_content_type, + 1); + + EXPECT_EQ(test.expected_content_type, + content_resource_type_provider()->GetContentType(request->url())); + + // Querying for the content type of |request->url()| again should still + // give the correct result. + EXPECT_EQ(test.expected_content_type, + content_resource_type_provider()->GetContentType(request->url())); + + if (test.expected_content_type == + ResourceTypeProvider::CONTENT_TYPE_MEDIA) { + EXPECT_EQ(net::ProxyServer::Direct(), request->proxy_server()); + } else { + EXPECT_EQ(unspecified, request->proxy_server()); + } } }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc index be76a72..9ff9687 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
@@ -28,7 +28,6 @@ #include "components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h" -#include "components/data_reduction_proxy/core/common/data_reduction_proxy_server.h" #include "components/data_use_measurement/core/data_use_user_data.h" #include "components/variations/variations_associated_data.h" #include "net/base/host_port_pair.h" @@ -407,13 +406,10 @@ DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(configurator_); - const std::vector<net::ProxyServer> proxies_for_http = - DataReductionProxyServer::ConvertToNetProxyServers( - config_values_->proxies_for_http()); if (enabled_by_user_ && !config_values_->holdback() && - !proxies_for_http.empty()) { + !config_values_->proxies_for_http().empty()) { configurator_->Enable(!secure_proxy_allowed_ || is_captive_portal_, - proxies_for_http); + config_values_->proxies_for_http()); } else { configurator_->Disable(); } @@ -435,28 +431,37 @@ if (!proxy_server.is_valid() || proxy_server.is_direct()) return false; - const std::vector<net::ProxyServer> proxy_list = - DataReductionProxyServer::ConvertToNetProxyServers( - config_values_->proxies_for_http()); + // Only compare the host port pair of the |proxy_server| since the proxy + // scheme of the stored data reduction proxy may be different than the proxy + // scheme of |proxy_server|. This may happen even when the |proxy_server| is a + // valid data reduction proxy. As an example, the stored data reduction proxy + // may have a proxy scheme of HTTPS while |proxy_server| may have QUIC as the + // proxy scheme. + const net::HostPortPair& host_port_pair = proxy_server.host_port_pair(); - net::HostPortPair host_port_pair = proxy_server.host_port_pair(); - const auto proxy_it = - std::find_if(proxy_list.begin(), proxy_list.end(), - [&host_port_pair](const net::ProxyServer& proxy) { - return proxy.is_valid() && - proxy.host_port_pair().Equals(host_port_pair); - }); + const std::vector<DataReductionProxyServer>& data_reduction_proxy_servers = + config_values_->proxies_for_http(); - if (proxy_it != proxy_list.end()) { - if (proxy_info) { - proxy_info->proxy_servers = - std::vector<net::ProxyServer>(proxy_it, proxy_list.end()); - proxy_info->proxy_index = - static_cast<size_t>(proxy_it - proxy_list.begin()); - } + const auto proxy_it = std::find_if( + data_reduction_proxy_servers.begin(), data_reduction_proxy_servers.end(), + [&host_port_pair](const DataReductionProxyServer& proxy) { + return proxy.proxy_server().is_valid() && + proxy.proxy_server().host_port_pair().Equals(host_port_pair); + }); + + if (proxy_it == data_reduction_proxy_servers.end()) + return false; + + if (!proxy_info) return true; - } - return false; + + proxy_info->proxy_servers = + DataReductionProxyServer::ConvertToNetProxyServers( + std::vector<DataReductionProxyServer>( + proxy_it, data_reduction_proxy_servers.end())); + proxy_info->proxy_index = + static_cast<size_t>(proxy_it - data_reduction_proxy_servers.begin()); + return true; } bool DataReductionProxyConfig::IsBypassedByDataReductionProxyLocalRules( @@ -1035,13 +1040,25 @@ } net::ProxyConfig DataReductionProxyConfig::ProxyConfigIgnoringHoldback() const { - std::vector<net::ProxyServer> proxies_for_http = - DataReductionProxyServer::ConvertToNetProxyServers( - config_values_->proxies_for_http()); - if (!enabled_by_user_ || proxies_for_http.empty()) + if (!enabled_by_user_ || config_values_->proxies_for_http().empty()) return net::ProxyConfig::CreateDirect(); return configurator_->CreateProxyConfig(!secure_proxy_allowed_, - proxies_for_http); + config_values_->proxies_for_http()); +} + +bool DataReductionProxyConfig::secure_proxy_allowed() const { + DCHECK(thread_checker_.CalledOnValidThread()); + return secure_proxy_allowed_; +} + +std::vector<DataReductionProxyServer> +DataReductionProxyConfig::GetProxiesForHttp() const { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (!enabled_by_user_) + return std::vector<DataReductionProxyServer>(); + + return config_values_->proxies_for_http(); } } // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h index 6cad47d..fe9eb76 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
@@ -18,6 +18,7 @@ #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" #include "base/time/time.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_server.h" #include "net/base/net_errors.h" #include "net/base/network_change_notifier.h" #include "net/base/network_interfaces.h" @@ -202,6 +203,10 @@ // This should only be used for logging purposes. net::ProxyConfig ProxyConfigIgnoringHoldback() const; + bool secure_proxy_allowed() const; + + std::vector<DataReductionProxyServer> GetProxiesForHttp() const; + protected: // Virtualized for mocking. Returns the list of network interfaces in use. // |interfaces| can be null.
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc index 92467e26..1a5cffc 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
@@ -573,11 +573,14 @@ EXPECT_FALSE(config_client()->foreground_fetch_pending()); #endif - std::vector<net::ProxyServer> http_proxies; - http_proxies.push_back( - net::ProxyServer::FromURI(kSuccessOrigin, net::ProxyServer::SCHEME_HTTP)); - http_proxies.push_back(net::ProxyServer::FromURI( - kSuccessFallback, net::ProxyServer::SCHEME_HTTP)); + std::vector<DataReductionProxyServer> http_proxies; + http_proxies.push_back(DataReductionProxyServer( + net::ProxyServer::FromURI(kSuccessOrigin, net::ProxyServer::SCHEME_HTTP), + ProxyServer::CORE)); + http_proxies.push_back(DataReductionProxyServer( + net::ProxyServer::FromURI(kSuccessFallback, + net::ProxyServer::SCHEME_HTTP), + ProxyServer::CORE)); // Secure check failed. configurator()->Enable(true /* secure_transport_restricted */, http_proxies); @@ -702,11 +705,14 @@ RunUntilIdle(); VerifyRemoteSuccess(true); - std::vector<net::ProxyServer> http_proxies; - http_proxies.push_back( - net::ProxyServer::FromURI(kSuccessOrigin, net::ProxyServer::SCHEME_HTTP)); - http_proxies.push_back(net::ProxyServer::FromURI( - kSuccessFallback, net::ProxyServer::SCHEME_HTTP)); + std::vector<DataReductionProxyServer> http_proxies; + http_proxies.push_back(DataReductionProxyServer( + net::ProxyServer::FromURI(kSuccessOrigin, net::ProxyServer::SCHEME_HTTP), + ProxyServer::CORE)); + http_proxies.push_back(DataReductionProxyServer( + net::ProxyServer::FromURI(kSuccessFallback, + net::ProxyServer::SCHEME_HTTP), + ProxyServer::CORE)); // Secure check failed. configurator()->Enable(true /* secure_transport_restricted */, http_proxies);
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.cc index e20ae9a..2c26c16 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.cc
@@ -12,6 +12,7 @@ #include "base/strings/string_util.h" #include "base/values.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_util.h" #include "net/proxy/proxy_config.h" namespace data_reduction_proxy { @@ -31,28 +32,32 @@ void DataReductionProxyConfigurator::Enable( bool secure_transport_restricted, - const std::vector<net::ProxyServer>& proxies_for_http) { + const std::vector<DataReductionProxyServer>& proxies_for_http) { DCHECK(thread_checker_.CalledOnValidThread()); net::ProxyConfig config = CreateProxyConfig(secure_transport_restricted, proxies_for_http); data_reduction_proxy_event_creator_->AddProxyEnabledEvent( - net_log_, secure_transport_restricted, proxies_for_http); + net_log_, secure_transport_restricted, + DataReductionProxyServer::ConvertToNetProxyServers(proxies_for_http)); config_ = config; } net::ProxyConfig DataReductionProxyConfigurator::CreateProxyConfig( bool secure_transport_restricted, - const std::vector<net::ProxyServer>& proxies_for_http) const { + const std::vector<DataReductionProxyServer>& proxies_for_http) const { DCHECK(thread_checker_.CalledOnValidThread()); + net::ProxyConfig config; + DCHECK(!config.is_valid() && config.proxy_rules().proxies_for_http.IsEmpty()); config.proxy_rules().type = net::ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME; for (const auto& http_proxy : proxies_for_http) { if (!secure_transport_restricted || - (http_proxy.scheme() != net::ProxyServer::SCHEME_HTTPS && - http_proxy.scheme() != net::ProxyServer::SCHEME_QUIC)) { - config.proxy_rules().proxies_for_http.AddProxyServer(http_proxy); + (http_proxy.proxy_server().scheme() != net::ProxyServer::SCHEME_HTTPS && + http_proxy.proxy_server().scheme() != net::ProxyServer::SCHEME_QUIC)) { + config.proxy_rules().proxies_for_http.AddProxyServer( + http_proxy.proxy_server()); } } @@ -61,6 +66,11 @@ net::ProxyServer::Direct()); } + if (config.proxy_rules().proxies_for_http.IsEmpty()) { + // Return an invalid net config so that data reduction proxy is not used. + return config; + } + config.proxy_rules().bypass_rules.ParseFromString( base::JoinString(bypass_rules_, ", ")); // The ID is set to a bogus value. It cannot be left uninitialized, else the
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h index 55643234..c4d8e70 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h
@@ -11,6 +11,7 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/threading/thread_checker.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_server.h" #include "net/proxy/proxy_config.h" namespace net { @@ -37,8 +38,9 @@ // transports can not be used. // TODO: crbug.com/675764: Pass a vector of DataReductionProxyServer // instead of net::ProxyServer. - virtual void Enable(bool secure_transport_restricted, - const std::vector<net::ProxyServer>& proxies_for_http); + virtual void Enable( + bool secure_transport_restricted, + const std::vector<DataReductionProxyServer>& proxies_for_http); // Constructs a proxy configuration suitable for disabling the Data Reduction // proxy. @@ -60,7 +62,7 @@ // over secure transports (HTTPS) should/can not be used. net::ProxyConfig CreateProxyConfig( bool secure_transport_restricted, - const std::vector<net::ProxyServer>& proxies_for_http) const; + const std::vector<DataReductionProxyServer>& proxies_for_http) const; private: FRIEND_TEST_ALL_PREFIXES(DataReductionProxyConfiguratorTest, TestBypassList);
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc index 4b20b339..a98ba92 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc
@@ -10,6 +10,7 @@ #include "base/values.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_server.h" #include "net/proxy/proxy_server.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -24,20 +25,21 @@ test_context_->net_log(), test_context_->event_creator())); } - std::vector<net::ProxyServer> BuildProxyList(const std::string& first, - const std::string& second) { - std::vector<net::ProxyServer> proxies; + std::vector<DataReductionProxyServer> BuildProxyList( + const std::string& first, + const std::string& second) { + std::vector<DataReductionProxyServer> proxies; if (!first.empty()) { net::ProxyServer proxy = net::ProxyServer::FromURI(first, net::ProxyServer::SCHEME_HTTP); EXPECT_TRUE(proxy.is_valid()) << first; - proxies.push_back(proxy); + proxies.push_back(DataReductionProxyServer(proxy, ProxyServer::CORE)); } if (!second.empty()) { net::ProxyServer proxy = net::ProxyServer::FromURI(second, net::ProxyServer::SCHEME_HTTP); EXPECT_TRUE(proxy.is_valid()) << second; - proxies.push_back(proxy); + proxies.push_back(DataReductionProxyServer(proxy, ProxyServer::CORE)); } return proxies; }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc index 7324f68..a9c344e 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
@@ -77,7 +77,28 @@ DCHECK(result); DCHECK(thread_checker_.CalledOnValidThread()); - OnResolveProxyHandler(url, method, configurator_->GetProxyConfig(), + ResourceTypeProvider::ContentType content_type = + ResourceTypeProvider::CONTENT_TYPE_UNKNOWN; + + if (io_data_ && io_data_->resource_type_provider()) { + content_type = io_data_->resource_type_provider()->GetContentType(url); + } + + std::vector<DataReductionProxyServer> proxies_for_http = + config_->GetProxiesForHttp(); + + // Remove the proxies that are unsupported for this request. + proxies_for_http.erase( + std::remove_if(proxies_for_http.begin(), proxies_for_http.end(), + [content_type](const DataReductionProxyServer& proxy) { + return !proxy.SupportsResourceType(content_type); + }), + proxies_for_http.end()); + + net::ProxyConfig proxy_config = configurator_->CreateProxyConfig( + !config_->secure_proxy_allowed(), proxies_for_http); + + OnResolveProxyHandler(url, method, proxy_config, proxy_service.proxy_retry_info(), config_, io_data_, result); @@ -251,24 +272,25 @@ last_network_change_time_ = tick_clock_->NowTicks(); } -void OnResolveProxyHandler(const GURL& url, - const std::string& method, - const net::ProxyConfig& data_reduction_proxy_config, - const net::ProxyRetryInfoMap& proxy_retry_info, - const DataReductionProxyConfig* config, - DataReductionProxyIOData* io_data, - net::ProxyInfo* result) { - DCHECK(config); +void OnResolveProxyHandler( + const GURL& url, + const std::string& method, + const net::ProxyConfig& proxy_config, + const net::ProxyRetryInfoMap& proxy_retry_info, + const DataReductionProxyConfig* data_reduction_proxy_config, + DataReductionProxyIOData* io_data, + net::ProxyInfo* result) { + DCHECK(data_reduction_proxy_config); DCHECK(result->is_empty() || result->is_direct() || - !config->IsDataReductionProxy(result->proxy_server(), NULL)); + !data_reduction_proxy_config->IsDataReductionProxy( + result->proxy_server(), NULL)); if (!util::EligibleForDataReductionProxy(*result, url, method)) return; net::ProxyInfo data_reduction_proxy_info; bool data_saver_proxy_used = util::ApplyProxyConfigToProxyInfo( - data_reduction_proxy_config, proxy_retry_info, url, - &data_reduction_proxy_info); + proxy_config, proxy_retry_info, url, &data_reduction_proxy_info); if (data_saver_proxy_used) result->OverrideProxyList(data_reduction_proxy_info.proxy_list()); @@ -279,17 +301,15 @@ UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.ResourceContentType", content_type, ResourceTypeProvider::CONTENT_TYPE_MAX); - // TODO(tbansal): crbug.com/671810: Use the content type to determine the - // proxy that should be used for fetching |url|. } - // The |data_reduction_proxy_config| must be valid otherwise the proxy - // cannot be used. - DCHECK(data_reduction_proxy_config.is_valid() || !data_saver_proxy_used); + // The |proxy_config| must be valid otherwise the proxy cannot be used. + DCHECK(proxy_config.is_valid() || !data_saver_proxy_used); - if (config->enabled_by_user_and_reachable() && url.SchemeIsHTTPOrHTTPS() && - !url.SchemeIsCryptographic() && !net::IsLocalhost(url.host()) && - (!data_reduction_proxy_config.is_valid() || data_saver_proxy_used)) { + if (data_reduction_proxy_config->enabled_by_user_and_reachable() && + url.SchemeIsHTTPOrHTTPS() && !url.SchemeIsCryptographic() && + !net::IsLocalhost(url.host()) && + (!proxy_config.is_valid() || data_saver_proxy_used)) { UMA_HISTOGRAM_BOOLEAN("DataReductionProxy.ConfigService.HTTPRequests", data_saver_proxy_used); }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h index fadac3e..2b54b467 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h
@@ -152,13 +152,14 @@ // not bypassed. Also, configures |result| to proceed directly to the origin if // |result|'s current proxy is the data reduction proxy // This is visible for test purposes. -void OnResolveProxyHandler(const GURL& url, - const std::string& method, - const net::ProxyConfig& data_reduction_proxy_config, - const net::ProxyRetryInfoMap& proxy_retry_info, - const DataReductionProxyConfig* config, - DataReductionProxyIOData* io_data, - net::ProxyInfo* result); +void OnResolveProxyHandler( + const GURL& url, + const std::string& method, + const net::ProxyConfig& proxy_config, + const net::ProxyRetryInfoMap& proxy_retry_info, + const DataReductionProxyConfig* data_reduction_proxy_config, + DataReductionProxyIOData* io_data, + net::ProxyInfo* result); } // namespace data_reduction_proxy #endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_DELEGATE_H_
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc index 905160c4..acb1d468 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc
@@ -46,7 +46,7 @@ return holdback_; } -const std::vector<DataReductionProxyServer> +const std::vector<DataReductionProxyServer>& DataReductionProxyMutableConfigValues::proxies_for_http() const { DCHECK(thread_checker_.CalledOnValidThread()); if (use_override_proxies_for_http_ && !proxies_for_http_.empty()) {
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h index 18374527..c1906082 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h
@@ -42,7 +42,8 @@ // Overrides of |DataReductionProxyConfigValues| bool promo_allowed() const override; bool holdback() const override; - const std::vector<DataReductionProxyServer> proxies_for_http() const override; + const std::vector<DataReductionProxyServer>& proxies_for_http() + const override; const GURL& secure_proxy_check_url() const override; protected:
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h index 15c4579..c2f79e9b 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h
@@ -27,7 +27,7 @@ virtual bool holdback() const = 0; // Returns the HTTP proxy servers to be used. - virtual const std::vector<DataReductionProxyServer> proxies_for_http() + virtual const std::vector<DataReductionProxyServer>& proxies_for_http() const = 0; // Returns the URL to check to decide if the secure proxy origin should be
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store_unittest.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store_unittest.cc index b790a00..a380e3b 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store_unittest.cc +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store_unittest.cc
@@ -19,6 +19,7 @@ #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_server.h" #include "net/base/host_port_pair.h" #include "net/base/net_errors.h" #include "net/http/http_status_code.h" @@ -220,11 +221,15 @@ EXPECT_EQ(std::string(), event_store()->GetHttpProxyList()); EXPECT_EQ(std::string(), event_store()->SanitizedLastBypassEvent()); - std::vector<net::ProxyServer> http_proxies; - http_proxies.push_back(net::ProxyServer(net::ProxyServer::SCHEME_HTTP, - net::HostPortPair("foo.com", 80))); - http_proxies.push_back(net::ProxyServer(net::ProxyServer::SCHEME_HTTPS, - net::HostPortPair("bar.com", 443))); + std::vector<DataReductionProxyServer> http_proxies; + http_proxies.push_back(DataReductionProxyServer( + net::ProxyServer(net::ProxyServer::SCHEME_HTTP, + net::HostPortPair("foo.com", 80)), + ProxyServer::CORE)); + http_proxies.push_back(DataReductionProxyServer( + net::ProxyServer(net::ProxyServer::SCHEME_HTTPS, + net::HostPortPair("bar.com", 443)), + ProxyServer::CORE)); configurator.Enable(false, http_proxies); EXPECT_EQ("foo.com:80;https://bar.com:443", event_store()->GetHttpProxyList()); @@ -235,7 +240,7 @@ TEST_F(DataReductionProxyEventStoreTest, TestFeedbackLastBypassEventFullURL) { DataReductionProxyConfigurator configurator(net_log(), event_creator()); - std::vector<net::ProxyServer> http_proxies; + std::vector<DataReductionProxyServer> http_proxies; configurator.Enable(false, http_proxies); std::unique_ptr<base::DictionaryValue> bypass_event( @@ -268,7 +273,7 @@ TEST_F(DataReductionProxyEventStoreTest, TestFeedbackLastBypassEventHostOnly) { DataReductionProxyConfigurator configurator(net_log(), event_creator()); - std::vector<net::ProxyServer> http_proxies; + std::vector<DataReductionProxyServer> http_proxies; configurator.Enable(false, http_proxies); std::unique_ptr<base::DictionaryValue> bypass_event(
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc index 8b9433ca..63f6080 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
@@ -467,7 +467,7 @@ secure_proxy_check_url_ = GURL(secure_proxy_check_url); } -const std::vector<DataReductionProxyServer> +const std::vector<DataReductionProxyServer>& DataReductionProxyParams::proxies_for_http() const { if (use_override_proxies_for_http_) return override_data_reduction_proxy_servers_;
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h index f7bdf3b..c44358df 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
@@ -197,7 +197,8 @@ ~DataReductionProxyParams() override; - const std::vector<DataReductionProxyServer> proxies_for_http() const override; + const std::vector<DataReductionProxyServer>& proxies_for_http() + const override; const GURL& secure_proxy_check_url() const override;
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_server.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_server.cc index bddd81d4..ddb01aa 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_server.cc +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_server.cc
@@ -4,6 +4,8 @@ #include "components/data_reduction_proxy/core/common/data_reduction_proxy_server.h" +#include "base/logging.h" + namespace data_reduction_proxy { DataReductionProxyServer::DataReductionProxyServer( @@ -17,12 +19,33 @@ proxy_type_ == other.proxy_type_; } +bool DataReductionProxyServer::SupportsResourceType( + ResourceTypeProvider::ContentType content_type) const { + switch (proxy_type_) { + case ProxyServer_ProxyType_CORE: + return true; + case ProxyServer_ProxyType_UNSPECIFIED_TYPE: + switch (content_type) { + case ResourceTypeProvider::CONTENT_TYPE_UNKNOWN: + return true; + case ResourceTypeProvider::CONTENT_TYPE_MEDIA: + return false; + case ResourceTypeProvider::CONTENT_TYPE_MAX: + NOTREACHED(); + return true; + } + } + return true; +} + // static std::vector<net::ProxyServer> DataReductionProxyServer::ConvertToNetProxyServers( const std::vector<DataReductionProxyServer>& data_reduction_proxy_servers) { std::vector<net::ProxyServer> net_proxy_servers; - for (auto data_reduction_proxy_server : data_reduction_proxy_servers) + net_proxy_servers.reserve(data_reduction_proxy_servers.size()); + + for (const auto& data_reduction_proxy_server : data_reduction_proxy_servers) net_proxy_servers.push_back(data_reduction_proxy_server.proxy_server()); return net_proxy_servers; }
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_server.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_server.h index 4f6626fa..000267c7 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_server.h +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_server.h
@@ -7,6 +7,7 @@ #include <vector> +#include "components/data_reduction_proxy/core/common/resource_type_provider.h" #include "components/data_reduction_proxy/proto/client_config.pb.h" #include "net/proxy/proxy_server.h" @@ -25,7 +26,10 @@ bool operator==(const DataReductionProxyServer& other) const; - net::ProxyServer proxy_server() const { return proxy_server_; } + bool SupportsResourceType( + ResourceTypeProvider::ContentType content_type) const; + + const net::ProxyServer& proxy_server() const { return proxy_server_; } static std::vector<net::ProxyServer> ConvertToNetProxyServers( const std::vector<DataReductionProxyServer>&
diff --git a/components/display_compositor/buffer_queue.h b/components/display_compositor/buffer_queue.h index 6d5a2d33..7ac212e 100644 --- a/components/display_compositor/buffer_queue.h +++ b/components/display_compositor/buffer_queue.h
@@ -37,9 +37,9 @@ class GLHelper; // Provides a surface that manages its own buffers, backed by GpuMemoryBuffers -// created using CHROMIUM_gpu_memory_buffer_image. Double/triple buffering is -// implemented internally. Doublebuffering occurs if PageFlipComplete is called -// before the next BindFramebuffer call, otherwise it creates extra buffers. +// created using CHROMIUM_image. Double/triple buffering is implemented +// internally. Doublebuffering occurs if PageFlipComplete is called before the +// next BindFramebuffer call, otherwise it creates extra buffers. class DISPLAY_COMPOSITOR_EXPORT BufferQueue { public: BufferQueue(gpu::gles2::GLES2Interface* gl,
diff --git a/components/display_compositor/compositor_overlay_candidate_validator_ozone.cc b/components/display_compositor/compositor_overlay_candidate_validator_ozone.cc index a8f12b7..e26e237 100644 --- a/components/display_compositor/compositor_overlay_candidate_validator_ozone.cc +++ b/components/display_compositor/compositor_overlay_candidate_validator_ozone.cc
@@ -59,13 +59,13 @@ base::SplitStringPiece(strategies_string, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) { if (strategy_name == "single-fullscreen") { - strategies_instantiators.push_back( + strategies_instantiators_.push_back( base::Bind(MakeOverlayStrategy<cc::OverlayStrategyFullscreen>)); } else if (strategy_name == "single-on-top") { - strategies_instantiators.push_back( + strategies_instantiators_.push_back( base::Bind(MakeOverlayStrategy<cc::OverlayStrategySingleOnTop>)); } else if (strategy_name == "underlay") { - strategies_instantiators.push_back( + strategies_instantiators_.push_back( base::Bind(MakeOverlayStrategy<cc::OverlayStrategyUnderlay>)); } else { LOG(WARNING) << "Unrecognized overlay strategy " << strategy_name; @@ -78,7 +78,7 @@ void CompositorOverlayCandidateValidatorOzone::GetStrategies( cc::OverlayProcessor::StrategyList* strategies) { - for (auto& instantiator : strategies_instantiators) + for (auto& instantiator : strategies_instantiators_) strategies->push_back(instantiator.Run(this)); }
diff --git a/components/display_compositor/compositor_overlay_candidate_validator_ozone.h b/components/display_compositor/compositor_overlay_candidate_validator_ozone.h index 8f697c8..19bc4ad 100644 --- a/components/display_compositor/compositor_overlay_candidate_validator_ozone.h +++ b/components/display_compositor/compositor_overlay_candidate_validator_ozone.h
@@ -43,7 +43,7 @@ CompositorOverlayCandidateValidatorOzone*)>; // List callbacks used to instantiate OverlayProcessor::Strategy // as defined by |strategies_string| paramter in the constructor. - std::vector<StrategyInstantiator> strategies_instantiators; + std::vector<StrategyInstantiator> strategies_instantiators_; bool software_mirror_active_; DISALLOW_COPY_AND_ASSIGN(CompositorOverlayCandidateValidatorOzone);
diff --git a/components/display_compositor/gpu_compositor_frame_sink.cc b/components/display_compositor/gpu_compositor_frame_sink.cc index 9a6347f..e5d2781b5 100644 --- a/components/display_compositor/gpu_compositor_frame_sink.cc +++ b/components/display_compositor/gpu_compositor_frame_sink.cc
@@ -12,8 +12,7 @@ GpuCompositorFrameSinkDelegate* delegate, cc::SurfaceManager* surface_manager, const cc::FrameSinkId& frame_sink_id, - std::unique_ptr<cc::Display> display, - std::unique_ptr<cc::BeginFrameSource> begin_frame_source, + cc::Display* display, cc::mojom::MojoCompositorFrameSinkPrivateRequest compositor_frame_sink_private_request, cc::mojom::MojoCompositorFrameSinkClientPtr client) @@ -21,8 +20,9 @@ support_(this, surface_manager, frame_sink_id, - std::move(display), - std::move(begin_frame_source)), + display, + true /* handles_frame_sink_id_invalidation */, + true /* needs_sync_points */), surface_manager_(surface_manager), surface_tracker_(frame_sink_id), client_(std::move(client)),
diff --git a/components/display_compositor/gpu_compositor_frame_sink.h b/components/display_compositor/gpu_compositor_frame_sink.h index 2ccac29..df2a51c 100644 --- a/components/display_compositor/gpu_compositor_frame_sink.h +++ b/components/display_compositor/gpu_compositor_frame_sink.h
@@ -35,8 +35,7 @@ GpuCompositorFrameSinkDelegate* delegate, cc::SurfaceManager* surface_manager, const cc::FrameSinkId& frame_sink_id, - std::unique_ptr<cc::Display> display, - std::unique_ptr<cc::BeginFrameSource> begin_frame_source, + cc::Display* display, cc::mojom::MojoCompositorFrameSinkPrivateRequest private_request, cc::mojom::MojoCompositorFrameSinkClientPtr client);
diff --git a/components/display_compositor/gpu_display_compositor_frame_sink.cc b/components/display_compositor/gpu_display_compositor_frame_sink.cc index 892409a..a69dbe43 100644 --- a/components/display_compositor/gpu_display_compositor_frame_sink.cc +++ b/components/display_compositor/gpu_display_compositor_frame_sink.cc
@@ -20,38 +20,40 @@ : GpuCompositorFrameSink(delegate, surface_manager, frame_sink_id, - std::move(display), - std::move(begin_frame_source), + display.get(), std::move(compositor_frame_sink_private_request), std::move(client)), binding_(this, std::move(request)), - display_private_binding_(this, std::move(display_private_request)) { + display_private_binding_(this, std::move(display_private_request)), + display_begin_frame_source_(std::move(begin_frame_source)), + display_(std::move(display)) { binding_.set_connection_error_handler( base::Bind(&GpuDisplayCompositorFrameSink::OnClientConnectionLost, base::Unretained(this))); + display_->SetVisible(true); } GpuDisplayCompositorFrameSink::~GpuDisplayCompositorFrameSink() = default; void GpuDisplayCompositorFrameSink::SetDisplayVisible(bool visible) { DCHECK(support_.display()); - support_.display()->SetVisible(visible); + display_->SetVisible(visible); } void GpuDisplayCompositorFrameSink::ResizeDisplay(const gfx::Size& size) { DCHECK(support_.display()); - support_.display()->Resize(size); + display_->Resize(size); } void GpuDisplayCompositorFrameSink::SetDisplayColorSpace( const gfx::ColorSpace& color_space) { DCHECK(support_.display()); - support_.display()->SetColorSpace(color_space); + display_->SetColorSpace(color_space); } void GpuDisplayCompositorFrameSink::SetOutputIsSecure(bool secure) { DCHECK(support_.display()); - support_.display()->SetOutputIsSecure(secure); + display_->SetOutputIsSecure(secure); } } // namespace display_compositor
diff --git a/components/display_compositor/gpu_display_compositor_frame_sink.h b/components/display_compositor/gpu_display_compositor_frame_sink.h index 588ef75..ac3ad8b 100644 --- a/components/display_compositor/gpu_display_compositor_frame_sink.h +++ b/components/display_compositor/gpu_display_compositor_frame_sink.h
@@ -38,6 +38,12 @@ mojo::AssociatedBinding<cc::mojom::MojoCompositorFrameSink> binding_; mojo::AssociatedBinding<cc::mojom::DisplayPrivate> display_private_binding_; + // GpuCompositorFrameSink holds a Display and its BeginFrameSource. In the + // window server, the display root window's CompositorFrameSink will have a + // valid gpu::SurfaceHandle. + std::unique_ptr<cc::BeginFrameSource> display_begin_frame_source_; + std::unique_ptr<cc::Display> display_; + DISALLOW_COPY_AND_ASSIGN(GpuDisplayCompositorFrameSink); };
diff --git a/components/display_compositor/gpu_offscreen_compositor_frame_sink.cc b/components/display_compositor/gpu_offscreen_compositor_frame_sink.cc index e47474d..f14f8db 100644 --- a/components/display_compositor/gpu_offscreen_compositor_frame_sink.cc +++ b/components/display_compositor/gpu_offscreen_compositor_frame_sink.cc
@@ -18,7 +18,6 @@ surface_manager, frame_sink_id, nullptr, - nullptr, std::move(compositor_frame_sink_private_request), std::move(client)), binding_(this, std::move(request)) {
diff --git a/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.cc b/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.cc index 73c6133..46131fd 100644 --- a/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.cc +++ b/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.cc
@@ -27,7 +27,8 @@ DistillerJsRenderFrameObserver::~DistillerJsRenderFrameObserver() {} -void DistillerJsRenderFrameObserver::DidStartProvisionalLoad() { +void DistillerJsRenderFrameObserver::DidStartProvisionalLoad( + blink::WebDataSource* data_source) { RegisterMojoInterface(); }
diff --git a/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.h b/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.h index 93476b5..6ace08d 100644 --- a/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.h +++ b/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.h
@@ -27,7 +27,7 @@ ~DistillerJsRenderFrameObserver() override; // RenderFrameObserver implementation. - void DidStartProvisionalLoad() override; + void DidStartProvisionalLoad(blink::WebDataSource* data_source) override; void DidFinishLoad() override; void DidCreateScriptContext(v8::Local<v8::Context> context, int world_id) override;
diff --git a/components/domain_reliability/scheduler.cc b/components/domain_reliability/scheduler.cc index 20bd334..f598c94 100644 --- a/components/domain_reliability/scheduler.cc +++ b/components/domain_reliability/scheduler.cc
@@ -8,6 +8,7 @@ #include <algorithm> #include <utility> +#include "base/memory/ptr_util.h" #include "base/metrics/field_trial.h" #include "base/strings/string_number_conversions.h" #include "base/values.h" @@ -95,7 +96,7 @@ for (size_t i = 0; i < num_collectors; ++i) { collectors_.push_back( - new net::BackoffEntry(&backoff_policy_, time_)); + base::MakeUnique<net::BackoffEntry>(&backoff_policy_, time_)); } } @@ -137,7 +138,7 @@ VLOG(1) << "Upload to collector " << collector_index_ << (result.is_success() ? " succeeded." : " failed."); - net::BackoffEntry* backoff = collectors_[collector_index_]; + net::BackoffEntry* backoff = collectors_[collector_index_].get(); collector_index_ = kInvalidCollectorIndex; backoff->InformOfRequest(result.is_success()); @@ -184,7 +185,7 @@ } std::unique_ptr<base::ListValue> collectors_value(new base::ListValue()); - for (const auto* collector : collectors_) { + for (const auto& collector : collectors_) { std::unique_ptr<base::DictionaryValue> value(new base::DictionaryValue()); value->SetInteger("failures", collector->failure_count()); value->SetInteger("next_upload", @@ -245,7 +246,7 @@ size_t min_index = kInvalidCollectorIndex; for (size_t i = 0; i < collectors_.size(); ++i) { - net::BackoffEntry* backoff = collectors_[i]; + net::BackoffEntry* backoff = collectors_[i].get(); // If a collector is usable, use the first one in the list. if (!backoff->ShouldRejectRequest()) { min_time = now;
diff --git a/components/domain_reliability/scheduler.h b/components/domain_reliability/scheduler.h index 97f598f..cf86a2d7 100644 --- a/components/domain_reliability/scheduler.h +++ b/components/domain_reliability/scheduler.h
@@ -11,7 +11,6 @@ #include <vector> #include "base/callback.h" -#include "base/memory/scoped_vector.h" #include "base/time/time.h" #include "components/domain_reliability/domain_reliability_export.h" #include "components/domain_reliability/uploader.h" @@ -102,7 +101,7 @@ Params params_; ScheduleUploadCallback callback_; net::BackoffEntry::Policy backoff_policy_; - ScopedVector<net::BackoffEntry> collectors_; + std::vector<std::unique_ptr<net::BackoffEntry>> collectors_; // Whether there are beacons that have not yet been uploaded. Set when a // beacon arrives or an upload fails, and cleared when an upload starts. @@ -141,6 +140,8 @@ base::TimeTicks last_upload_end_time_; size_t last_upload_collector_index_; bool last_upload_success_; + + DISALLOW_COPY_AND_ASSIGN(DomainReliabilityScheduler); }; } // namespace domain_reliability
diff --git a/components/exo/compositor_frame_sink.cc b/components/exo/compositor_frame_sink.cc index 59a3ea4a..28e94a8 100644 --- a/components/exo/compositor_frame_sink.cc +++ b/components/exo/compositor_frame_sink.cc
@@ -18,7 +18,12 @@ CompositorFrameSink::CompositorFrameSink(const cc::FrameSinkId& frame_sink_id, cc::SurfaceManager* surface_manager, CompositorFrameSinkHolder* client) - : support_(this, surface_manager, frame_sink_id, nullptr, nullptr), + : support_(this, + surface_manager, + frame_sink_id, + nullptr, + true /* handles_frame_sink_id_invalidation */, + true /* needs_sync_points */), client_(client) {} CompositorFrameSink::~CompositorFrameSink() {}
diff --git a/components/gcm_driver/OWNERS b/components/gcm_driver/OWNERS index af1d4150..3cba11c 100644 --- a/components/gcm_driver/OWNERS +++ b/components/gcm_driver/OWNERS
@@ -3,3 +3,5 @@ jianli@chromium.org peter@chromium.org zea@chromium.org + +# COMPONENT: Services>CloudMessaging
diff --git a/components/metrics/BUILD.gn b/components/metrics/BUILD.gn index 78341404..300bb1d 100644 --- a/components/metrics/BUILD.gn +++ b/components/metrics/BUILD.gn
@@ -367,3 +367,14 @@ deps -= [ "//components/metrics/public/cpp:call_stack_unit_tests" ] } } + +# Convenience testing target +test("metrics_unittests") { + sources = [ + "//components/test/run_all_unittests.cc", + ] + deps = [ + ":unit_tests", + "//components/test:test_support", + ] +}
diff --git a/components/ntp_snippets/category.cc b/components/ntp_snippets/category.cc index 7274a01..0a3fc04 100644 --- a/components/ntp_snippets/category.cc +++ b/components/ntp_snippets/category.cc
@@ -22,7 +22,9 @@ // static Category Category::FromIDValue(int id) { - DCHECK(IsValidIDValue(id)) << "Not a valid ID: " << id; + DCHECK(IsValidIDValue(id)) << id << " is not a valid category ID. This may " + "have been caused by removal of a local " + "KnownCategory."; return Category(id); }
diff --git a/components/ntp_snippets/category.h b/components/ntp_snippets/category.h index 6e36a3a..d3859fb 100644 --- a/components/ntp_snippets/category.h +++ b/components/ntp_snippets/category.h
@@ -33,7 +33,11 @@ // Pages recently browsed to on other devices. FOREIGN_TABS, - // INSERT NEW LOCAL CATEGORIES HERE! + + // ****************** INSERT NEW LOCAL CATEGORIES HERE! ****************** + // Existing categories are persisted and they must never be removed. This may + // happen implicitly, e.g. when an older version without some local category + // is installed. // Follows the last local category. LOCAL_CATEGORIES_COUNT, @@ -43,7 +47,8 @@ // Articles for you. ARTICLES, - // INSERT NEW REMOTE CATEGORIES HERE! + + // ****************** INSERT NEW REMOTE CATEGORIES HERE! ****************** // Tracks the last known remote category LAST_KNOWN_REMOTE_CATEGORY = ARTICLES,
diff --git a/components/ntp_tiles/most_visited_sites.cc b/components/ntp_tiles/most_visited_sites.cc index 379e107..6df20e3 100644 --- a/components/ntp_tiles/most_visited_sites.cc +++ b/components/ntp_tiles/most_visited_sites.cc
@@ -78,6 +78,21 @@ supervisor_->SetObserver(nullptr); } +bool MostVisitedSites::DoesSourceExist(NTPTileSource source) const { + switch (source) { + case NTPTileSource::TOP_SITES: + return top_sites_ != nullptr; + case NTPTileSource::SUGGESTIONS_SERVICE: + return suggestions_service_ != nullptr; + case NTPTileSource::POPULAR: + return popular_sites_ != nullptr; + case NTPTileSource::WHITELIST: + return supervisor_ != nullptr; + } + NOTREACHED(); + return false; +} + void MostVisitedSites::SetMostVisitedURLsObserver(Observer* observer, int num_sites) { DCHECK(observer); @@ -192,10 +207,8 @@ std::min(visited_list.size(), static_cast<size_t>(num_sites_)); for (size_t i = 0; i < num_tiles; ++i) { const history::MostVisitedURL& visited = visited_list[i]; - if (visited.url.is_empty()) { - num_tiles = i; + if (visited.url.is_empty()) break; // This is the signal that there are no more real visited sites. - } if (supervisor_ && supervisor_->IsBlocked(visited.url)) continue;
diff --git a/components/ntp_tiles/most_visited_sites.h b/components/ntp_tiles/most_visited_sites.h index 1b987c2..5df1fc66 100644 --- a/components/ntp_tiles/most_visited_sites.h +++ b/components/ntp_tiles/most_visited_sites.h
@@ -101,6 +101,19 @@ ~MostVisitedSites() override; + // Returns true if this object was created with a non-null provider for the + // given NTP tile source. That source may or may not actually provide tiles, + // depending on its configuration and the priority of different sources. + bool DoesSourceExist(NTPTileSource source) const; + + // Returns the corresponding object passed at construction. + history::TopSites* top_sites() { return top_sites_.get(); } + suggestions::SuggestionsService* suggestions() { + return suggestions_service_; + } + PopularSites* popular_sites() { return popular_sites_.get(); } + MostVisitedSitesSupervisor* supervisor() { return supervisor_.get(); } + // Sets the observer, and immediately fetches the current suggestions. // Does not take ownership of |observer|, which must outlive this object and // must not be null.
diff --git a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc index 9f876ee..e87440e2 100644 --- a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc +++ b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
@@ -6,8 +6,12 @@ #include "base/bind.h" #include "base/callback.h" +#include "base/files/file_util.h" +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" #include "base/logging.h" #include "base/memory/ptr_util.h" +#include "base/task_runner_util.h" #include "base/values.h" #include "components/ntp_tiles/most_visited_sites.h" #include "components/ntp_tiles/pref_names.h" @@ -18,13 +22,25 @@ namespace ntp_tiles { +namespace { + +std::string FormatJson(const base::Value& value) { + std::string pretty_printed; + bool ok = base::JSONWriter::WriteWithOptions( + value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &pretty_printed); + DCHECK(ok); + return pretty_printed; +} + +} // namespace + NTPTilesInternalsMessageHandlerClient::NTPTilesInternalsMessageHandlerClient() = default; NTPTilesInternalsMessageHandlerClient:: ~NTPTilesInternalsMessageHandlerClient() = default; NTPTilesInternalsMessageHandler::NTPTilesInternalsMessageHandler() - : client_(nullptr), site_count_(8) {} + : client_(nullptr), site_count_(8), weak_ptr_factory_(this) {} NTPTilesInternalsMessageHandler::~NTPTilesInternalsMessageHandler() = default; @@ -40,6 +56,16 @@ client_->RegisterMessageCallback( "update", base::Bind(&NTPTilesInternalsMessageHandler::HandleUpdate, base::Unretained(this))); + + client_->RegisterMessageCallback( + "fetchSuggestions", + base::Bind(&NTPTilesInternalsMessageHandler::HandleFetchSuggestions, + base::Unretained(this))); + + client_->RegisterMessageCallback( + "viewPopularSitesJson", + base::Bind(&NTPTilesInternalsMessageHandler::HandleViewPopularSitesJson, + base::Unretained(this))); } void NTPTilesInternalsMessageHandler::HandleRegisterForEvents( @@ -49,10 +75,11 @@ } DCHECK(args->empty()); - SendSourceInfo(); - + suggestions_status_.clear(); + popular_sites_json_.clear(); most_visited_sites_ = client_->MakeMostVisitedSites(); most_visited_sites_->SetMostVisitedURLsObserver(this, site_count_); + SendSourceInfo(); } void NTPTilesInternalsMessageHandler::HandleUpdate( @@ -67,7 +94,9 @@ PrefService* prefs = client_->GetPrefs(); - if (client_->DoesSourceExist(ntp_tiles::NTPTileSource::POPULAR)) { + if (most_visited_sites_->DoesSourceExist(ntp_tiles::NTPTileSource::POPULAR)) { + popular_sites_json_.clear(); + std::string url; dict->GetString("popular.overrideURL", &url); if (url.empty()) { @@ -102,20 +131,53 @@ SendSourceInfo(); } +void NTPTilesInternalsMessageHandler::HandleFetchSuggestions( + const base::ListValue* args) { + DCHECK_EQ(0u, args->GetSize()); + if (!most_visited_sites_->DoesSourceExist( + ntp_tiles::NTPTileSource::SUGGESTIONS_SERVICE)) { + return; + } + + if (most_visited_sites_->suggestions()->FetchSuggestionsData()) { + suggestions_status_ = "fetching..."; + } else { + suggestions_status_ = "history sync is disabled, or not yet initialized"; + } + SendSourceInfo(); +} + +void NTPTilesInternalsMessageHandler::HandleViewPopularSitesJson( + const base::ListValue* args) { + DCHECK_EQ(0u, args->GetSize()); + if (!most_visited_sites_->DoesSourceExist( + ntp_tiles::NTPTileSource::POPULAR)) { + return; + } + + popular_sites_json_ = FormatJson( + *most_visited_sites_->popular_sites()->GetCachedJson()); + SendSourceInfo(); +} + void NTPTilesInternalsMessageHandler::SendSourceInfo() { PrefService* prefs = client_->GetPrefs(); base::DictionaryValue value; - value.SetBoolean("topSites", - client_->DoesSourceExist(NTPTileSource::TOP_SITES)); - value.SetBoolean( - "suggestionsService", - client_->DoesSourceExist(NTPTileSource::SUGGESTIONS_SERVICE)); - value.SetBoolean("whitelist", - client_->DoesSourceExist(NTPTileSource::WHITELIST)); + value.SetBoolean("topSites", most_visited_sites_->DoesSourceExist( + NTPTileSource::TOP_SITES)); + value.SetBoolean("whitelist", most_visited_sites_->DoesSourceExist( + NTPTileSource::WHITELIST)); - if (client_->DoesSourceExist(NTPTileSource::POPULAR)) { - auto popular_sites = client_->MakePopularSites(); + if (most_visited_sites_->DoesSourceExist( + NTPTileSource::SUGGESTIONS_SERVICE)) { + value.SetString("suggestionsService.status", suggestions_status_); + } else { + value.SetBoolean("suggestionsService", false); + } + + if (most_visited_sites_->DoesSourceExist(NTPTileSource::POPULAR)) { + auto popular_sites = most_visited_sites_->popular_sites(); value.SetString("popular.url", popular_sites->GetURLToFetch().spec()); value.SetString("popular.country", popular_sites->GetCountryToFetch()); value.SetString("popular.version", popular_sites->GetVersionToFetch()); @@ -129,6 +191,8 @@ value.SetString( "popular.overrideVersion", prefs->GetString(ntp_tiles::prefs::kPopularSitesOverrideVersion)); + + value.SetString("popular.json", popular_sites_json_); } else { value.SetBoolean("popular", false); }
diff --git a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h index 23727465..03b58c4 100644 --- a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h +++ b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h
@@ -10,6 +10,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "base/optional.h" #include "components/ntp_tiles/most_visited_sites.h" namespace base { @@ -39,6 +40,8 @@ // Callbacks registered in RegisterMessages(). void HandleRegisterForEvents(const base::ListValue* args); void HandleUpdate(const base::ListValue* args); + void HandleFetchSuggestions(const base::ListValue* args); + void HandleViewPopularSitesJson(const base::ListValue* args); void SendSourceInfo(); void SendTiles(const NTPTilesVector& tiles); @@ -53,6 +56,11 @@ int site_count_; std::unique_ptr<MostVisitedSites> most_visited_sites_; + std::string suggestions_status_; + std::string popular_sites_json_; + + base::WeakPtrFactory<NTPTilesInternalsMessageHandler> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(NTPTilesInternalsMessageHandler); };
diff --git a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler_client.h b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler_client.h index d26972d..d846361 100644 --- a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler_client.h +++ b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler_client.h
@@ -23,7 +23,6 @@ namespace ntp_tiles { class MostVisitedSites; -class PopularSites; // Implemented by embedders to hook up NTPTilesInternalsMessageHandler. class NTPTilesInternalsMessageHandlerClient { @@ -42,9 +41,6 @@ virtual std::unique_ptr<ntp_tiles::MostVisitedSites> MakeMostVisitedSites() = 0; - // Creates a new PopularSites based on the context pf the WebUI page. - virtual std::unique_ptr<ntp_tiles::PopularSites> MakePopularSites() = 0; - // Registers a callback in Javascript. See content::WebUI and web::WebUIIOS. virtual void RegisterMessageCallback( const std::string& message,
diff --git a/components/ntp_tiles/webui/popular_sites_internals_message_handler_client.h b/components/ntp_tiles/webui/popular_sites_internals_message_handler_client.h index 45797e24..43368f8 100644 --- a/components/ntp_tiles/webui/popular_sites_internals_message_handler_client.h +++ b/components/ntp_tiles/webui/popular_sites_internals_message_handler_client.h
@@ -17,7 +17,6 @@ namespace base { class Value; class ListValue; -class SequencedWorkerPool; } // namespace base namespace ntp_tiles { @@ -27,9 +26,6 @@ // Implemented by embedders to hook up PopularSitesInternalsMessageHandler. class PopularSitesInternalsMessageHandlerClient { public: - // Returns the blocking pool for hte embedder. - virtual base::SequencedWorkerPool* GetBlockingPool() = 0; - // Returns the PrefService for the embedder and containing WebUI page. virtual PrefService* GetPrefs() = 0;
diff --git a/components/ntp_tiles/webui/resources/ntp_tiles_internals.css b/components/ntp_tiles/webui/resources/ntp_tiles_internals.css index 6de21e50..bc219fb66 100644 --- a/components/ntp_tiles/webui/resources/ntp_tiles_internals.css +++ b/components/ntp_tiles/webui/resources/ntp_tiles_internals.css
@@ -49,6 +49,6 @@ width: 100%; } -#json-value { +#popular-json-value { font-size: 75%; }
diff --git a/components/ntp_tiles/webui/resources/ntp_tiles_internals.html b/components/ntp_tiles/webui/resources/ntp_tiles_internals.html index 0fb7e6f2..dfdfe36 100644 --- a/components/ntp_tiles/webui/resources/ntp_tiles_internals.html +++ b/components/ntp_tiles/webui/resources/ntp_tiles_internals.html
@@ -44,10 +44,15 @@ </tr> </tbody> <tbody jsselect="suggestionsService"> - <tr> + <tr jsdisplay="$this"> + <td class="detail"> + <input id="suggestions-fetch" type="submit" value="Fetch"></input> + </td> + <td class="value" jscontent="status"></td> + </tr> + <tr jsdisplay="!$this"> <td class="detail">enabled</td> - <td class="value" jsdisplay="$this">yes</td> - <td class="value" jsdisplay="!$this">no</td> + <td class="value">no</td> </tr> </tbody> <tbody jsselect="popular"> @@ -66,6 +71,12 @@ <td class="detail">Version</td> <td class="value"><input id="override-version" type="text" jsvalues="values:overrideVersion;placeholder:version"></td> </tr> + <tr jsdisplay="$this"> + <td class="detail"> + <input id="popular-view-json" type="submit", value="View JSON"></input> + </td> + <td class="value"><pre id="popular-json-value" jscontent="json"></pre></td> + </tr> <tr jsdisplay="!$this"> <td class="detail">enabled</td> <td class="value">no</td>
diff --git a/components/ntp_tiles/webui/resources/ntp_tiles_internals.js b/components/ntp_tiles/webui/resources/ntp_tiles_internals.js index bcb05d5e..dedcdf3 100644 --- a/components/ntp_tiles/webui/resources/ntp_tiles_internals.js +++ b/components/ntp_tiles/webui/resources/ntp_tiles_internals.js
@@ -16,7 +16,21 @@ "overrideCountry": $('override-country').value, "overrideVersion": $('override-version').value, }, - }]) + }]); + }); + + $('suggestions-fetch').addEventListener('click', function(event) { + event.preventDefault(); + chrome.send('fetchSuggestions'); + }); + + $('popular-view-json').addEventListener('click', function(event) { + event.preventDefault(); + if ($('popular-json-value').textContent === "") { + chrome.send('viewPopularSitesJson'); + } else { + $('popular-json-value').textContent = ""; + } }); chrome.send('registerForEvents');
diff --git a/components/offline_pages/content/background_loader/background_loader_contents.cc b/components/offline_pages/content/background_loader/background_loader_contents.cc index 5998fc78..3fb1907b 100644 --- a/components/offline_pages/content/background_loader/background_loader_contents.cc +++ b/components/offline_pages/content/background_loader/background_loader_contents.cc
@@ -13,6 +13,7 @@ : browser_context_(browser_context) { web_contents_.reset(content::WebContents::Create( content::WebContents::CreateParams(browser_context_))); + web_contents_->SetAudioMuted(true); web_contents_->SetDelegate(this); }
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn index 7b0fc11..2ba6a8a 100644 --- a/components/omnibox/browser/BUILD.gn +++ b/components/omnibox/browser/BUILD.gn
@@ -3,48 +3,25 @@ # found in the LICENSE file. import("//third_party/protobuf/proto_library.gni") +import("//ui/vector_icons/vector_icons.gni") if (is_android) { import("//build/config/android/rules.gni") } -action("aggregate_vector_icons") { - visibility = [ ":*" ] - - script = "//ui/gfx/vector_icons/aggregate_vector_icons.py" +aggregate_vector_icons("omnibox_vector_icons") { + icon_directory = "vector_icons" icons = [ - "vector_icons/calculator.1x.icon", - "vector_icons/calculator.icon", - "vector_icons/extension_app.1x.icon", - "vector_icons/extension_app.icon", - "vector_icons/http.icon", - "vector_icons/keyword_search.icon", - "vector_icons/search.icon", - "vector_icons/star.1x.icon", - "vector_icons/star.icon", - ] - - output_cc = "$target_gen_dir/vector_icons.cc" - output_h = "$target_gen_dir/vector_icons.h" - - inputs = icons - inputs += [ - "vector_icons/vector_icons.cc.template", - "vector_icons/vector_icons.h.template", - ] - outputs = [ - output_cc, - output_h, - ] - - response_file_contents = rebase_path(icons, root_build_dir) - - args = [ - "--working_directory=" + rebase_path("./vector_icons"), - "--file_list={{response_file_name}}", - "--output_cc=" + rebase_path(output_cc, root_build_dir), - "--output_h=" + rebase_path(output_h, root_build_dir), + "calculator.1x.icon", + "calculator.icon", + "extension_app.1x.icon", + "extension_app.icon", + "http.icon", + "keyword_search.icon", + "search.icon", + "star.1x.icon", + "star.icon", ] } @@ -188,8 +165,8 @@ ] if (!is_android && !is_ios) { - sources += get_target_outputs(":aggregate_vector_icons") - deps += [ ":aggregate_vector_icons" ] + sources += get_target_outputs(":omnibox_vector_icons") + deps += [ ":omnibox_vector_icons" ] } # TODO(brettw) Fix the include cycle and remove this line.
diff --git a/components/password_manager/OWNERS b/components/password_manager/OWNERS index bc2ebbb..206695fd 100644 --- a/components/password_manager/OWNERS +++ b/components/password_manager/OWNERS
@@ -5,3 +5,5 @@ mkwst@chromium.org vabr@chromium.org vasilii@chromium.org + +# COMPONENT: UI>Browser>Passwords
diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn index c76864f..6b7fe2d 100644 --- a/components/password_manager/core/browser/BUILD.gn +++ b/components/password_manager/core/browser/BUILD.gn
@@ -74,6 +74,8 @@ "login_database_win.cc", "login_model.cc", "login_model.h", + "obsolete_http_cleaner.cc", + "obsolete_http_cleaner.h", "password_autofill_manager.cc", "password_autofill_manager.h", "password_bubble_experiment.cc", @@ -281,6 +283,7 @@ "log_router_unittest.cc", "login_database_unittest.cc", "login_model_unittest.cc", + "obsolete_http_cleaner_unittest.cc", "password_autofill_manager_unittest.cc", "password_bubble_experiment_unittest.cc", "password_form_manager_unittest.cc",
diff --git a/components/password_manager/core/browser/obsolete_http_cleaner.cc b/components/password_manager/core/browser/obsolete_http_cleaner.cc new file mode 100644 index 0000000..c1daec4 --- /dev/null +++ b/components/password_manager/core/browser/obsolete_http_cleaner.cc
@@ -0,0 +1,118 @@ +// 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 "components/password_manager/core/browser/obsolete_http_cleaner.h" + +#include <algorithm> +#include <iterator> +#include <tuple> + +#include "base/logging.h" +#include "components/autofill/core/common/password_form.h" +#include "components/password_manager/core/browser/password_manager_client.h" +#include "components/password_manager/core/browser/password_store.h" +#include "components/password_manager/core/browser/statistics_table.h" +#include "url/url_constants.h" + +using autofill::PasswordForm; + +namespace password_manager { + +namespace { + +std::vector<std::unique_ptr<PasswordForm>> SplitFormsFrom( + std::vector<std::unique_ptr<PasswordForm>>::iterator from, + std::vector<std::unique_ptr<PasswordForm>>* forms) { + std::vector<std::unique_ptr<PasswordForm>> result; + result.reserve(std::distance(from, std::end(*forms))); + std::move(from, std::end(*forms), std::back_inserter(result)); + forms->erase(from, std::end(*forms)); + return result; +} + +} // namespace + +ObsoleteHttpCleaner::ObsoleteHttpCleaner(const PasswordManagerClient* client) + : client_(client) { + DCHECK(client_); +} + +ObsoleteHttpCleaner::~ObsoleteHttpCleaner() = default; + +void ObsoleteHttpCleaner::OnGetPasswordStoreResults( + std::vector<std::unique_ptr<PasswordForm>> results) { + // Non HTTP or HTTPS credentials are ignored. + results.erase(std::remove_if(std::begin(results), std::end(results), + [](const std::unique_ptr<PasswordForm>& form) { + return !form->origin.SchemeIsHTTPOrHTTPS(); + }), + std::end(results)); + + // Move HTTPS forms into their own container. + auto https_forms = SplitFormsFrom( + std::partition(std::begin(results), std::end(results), + [](const std::unique_ptr<PasswordForm>& form) { + return form->origin.SchemeIs(url::kHttpScheme); + }), + &results); + + // Move blacklisted HTTP forms into their own container. + const auto blacklisted_http_forms = SplitFormsFrom( + std::partition(std::begin(results), std::end(results), + [](const std::unique_ptr<PasswordForm>& form) { + return !form->blacklisted_by_user; + }), + &results); + + // Remove blacklisted HTTP forms from the password store when HSTS is active + // for the given host. + for (const auto& form : blacklisted_http_forms) { + if (client_->IsHSTSActiveForHost(form->origin)) + client_->GetPasswordStore()->RemoveLogin(*form); + } + + // Return early if there are no non-blacklisted HTTP forms. + if (results.empty()) + return; + + // Ignore non HSTS forms. + https_forms.erase( + std::remove_if(std::begin(https_forms), std::end(https_forms), + [this](const std::unique_ptr<PasswordForm>& form) { + return !client_->IsHSTSActiveForHost(form->origin); + }), + std::end(https_forms)); + + // Sort HSTS forms according to custom comparison function. Consider two forms + // equivalent if they have the same host, as well as the same username and + // password. + const auto form_cmp = [](const std::unique_ptr<PasswordForm>& lhs, + const std::unique_ptr<PasswordForm>& rhs) { + return std::forward_as_tuple(lhs->origin.host_piece(), lhs->username_value, + lhs->password_value) < + std::forward_as_tuple(rhs->origin.host_piece(), rhs->username_value, + rhs->password_value); + }; + + std::sort(std::begin(https_forms), std::end(https_forms), form_cmp); + + // Iterate through HTTP forms and remove them from the password store if there + // exists an equivalent HSTS form. + for (const auto& form : results) { + if (std::binary_search(std::begin(https_forms), std::end(https_forms), form, + form_cmp)) + client_->GetPasswordStore()->RemoveLogin(*form); + } +} + +void ObsoleteHttpCleaner::OnGetSiteStatistics( + std::vector<InteractionsStats> stats) { + for (const auto& stat : stats) { + if (stat.origin_domain.SchemeIs(url::kHttpScheme) && + client_->IsHSTSActiveForHost(stat.origin_domain)) + client_->GetPasswordStore()->RemoveSiteStats(stat.origin_domain); + } +} + +} // namespace password_manager
diff --git a/components/password_manager/core/browser/obsolete_http_cleaner.h b/components/password_manager/core/browser/obsolete_http_cleaner.h new file mode 100644 index 0000000..6b974e82 --- /dev/null +++ b/components/password_manager/core/browser/obsolete_http_cleaner.h
@@ -0,0 +1,50 @@ +// 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 COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_OBSOLETE_HTTP_CLEANER_H_ +#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_OBSOLETE_HTTP_CLEANER_H_ + +#include <memory> +#include <vector> + +#include "base/macros.h" +#include "components/password_manager/core/browser/password_store_consumer.h" + +namespace autofill { +struct PasswordForm; +} + +namespace password_manager { + +class PasswordManagerClient; + +// This class removes obsolete HTTP data from a password store. HTTP data is +// obsolete, if the corresponding host migrated to HTTPS and has HSTS enabled. +class ObsoleteHttpCleaner : public PasswordStoreConsumer { + public: + explicit ObsoleteHttpCleaner(const PasswordManagerClient* client); + ~ObsoleteHttpCleaner() override; + + // PasswordStoreConsumer: + // This will be called for both autofillable logins as well as blacklisted + // logins. Blacklisted logins are removed iff the scheme is HTTP and HSTS is + // enabled for the host. + // Autofillable logins are removed iff the scheme is HTTP and there exists + // another HTTPS login with active HSTS that has the same host as well as the + // same username and password. + void OnGetPasswordStoreResults( + std::vector<std::unique_ptr<autofill::PasswordForm>> results) override; + + // This will remove all stats for HTTP sites for which HSTS is active. + void OnGetSiteStatistics(std::vector<InteractionsStats> stats) override; + + private: + const PasswordManagerClient* const client_; + + DISALLOW_COPY_AND_ASSIGN(ObsoleteHttpCleaner); +}; + +} // namespace password_manager + +#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_OBSOLETE_HTTP_CLEANER_H_
diff --git a/components/password_manager/core/browser/obsolete_http_cleaner_unittest.cc b/components/password_manager/core/browser/obsolete_http_cleaner_unittest.cc new file mode 100644 index 0000000..7ae1fd70 --- /dev/null +++ b/components/password_manager/core/browser/obsolete_http_cleaner_unittest.cc
@@ -0,0 +1,233 @@ +// 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 "components/password_manager/core/browser/obsolete_http_cleaner.h" + +#include <ios> + +#include "base/memory/ptr_util.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/strings/utf_string_conversions.h" +#include "components/password_manager/core/browser/mock_password_store.h" +#include "components/password_manager/core/browser/stub_password_manager_client.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +using autofill::PasswordForm; +using testing::Return; + +namespace password_manager { + +namespace { + +constexpr char kTestHttpURL[] = "http://example.org/"; +constexpr char kTestHttpsURL[] = "https://example.org/"; + +PasswordForm CreateTestHTTPForm() { + PasswordForm form; + form.origin = GURL(kTestHttpURL); + form.signon_realm = form.origin.spec(); + form.action = form.origin; + form.username_value = base::ASCIIToUTF16("user"); + form.password_value = base::ASCIIToUTF16("password"); + return form; +} + +PasswordForm CreateTestHTTPSForm() { + PasswordForm form; + form.origin = GURL(kTestHttpsURL); + form.signon_realm = form.origin.spec(); + form.action = form.origin; + form.username_value = base::ASCIIToUTF16("user"); + form.password_value = base::ASCIIToUTF16("password"); + return form; +} + +InteractionsStats CreateTestHTTPStats() { + InteractionsStats stats; + stats.origin_domain = GURL(kTestHttpURL); + stats.username_value = base::ASCIIToUTF16("user"); + return stats; +} + +InteractionsStats CreateTestHTTPSStats() { + InteractionsStats stats; + stats.origin_domain = GURL(kTestHttpsURL); + stats.username_value = base::ASCIIToUTF16("user"); + return stats; +} + +// Small helper that wraps passed in forms in unique ptrs. +std::vector<std::unique_ptr<PasswordForm>> MakeResults( + const std::vector<PasswordForm>& forms) { + std::vector<std::unique_ptr<PasswordForm>> results; + results.reserve(forms.size()); + for (const auto& form : forms) + results.push_back(base::MakeUnique<PasswordForm>(form)); + return results; +} + +class MockPasswordManagerClient : public StubPasswordManagerClient { + public: + explicit MockPasswordManagerClient(PasswordStore* store) : store_(store) {} + + PasswordStore* GetPasswordStore() const override { return store_; } + MOCK_CONST_METHOD1(IsHSTSActiveForHost, bool(const GURL&)); + + private: + PasswordStore* store_; + + DISALLOW_COPY_AND_ASSIGN(MockPasswordManagerClient); +}; + +} // namespace + +class ObsoleteHttpCleanerTest : public testing::Test { + public: + ObsoleteHttpCleanerTest() + : mock_store_(new testing::StrictMock<MockPasswordStore>), + client_(mock_store_.get()) {} + ~ObsoleteHttpCleanerTest() override { mock_store_->ShutdownOnUIThread(); } + + MockPasswordStore& store() { return *mock_store_; } + MockPasswordManagerClient& client() { return client_; } + + private: + base::MessageLoop message_loop_; // Used by mock_store_. + scoped_refptr<MockPasswordStore> mock_store_; + MockPasswordManagerClient client_; + + DISALLOW_COPY_AND_ASSIGN(ObsoleteHttpCleanerTest); +}; + +TEST_F(ObsoleteHttpCleanerTest, TestBlacklistDeletion) { + struct TestCase { + bool is_http; + bool is_blacklisted; + bool is_hsts; + bool is_deleted; + }; + + constexpr static TestCase cases[] = { + {true, true, true, true}, {true, true, false, false}, + {true, false, true, false}, {true, false, false, false}, + {false, true, true, false}, {false, true, false, false}, + {false, false, true, false}, {false, false, false, false}, + }; + + ObsoleteHttpCleaner cleaner(&client()); + for (const auto& test_case : cases) { + SCOPED_TRACE(testing::Message() + << std::boolalpha + << "(is_http, is_blacklisted, is_hsts, is_deleted): (" + << test_case.is_http << ", " << test_case.is_blacklisted + << ", " << test_case.is_hsts << ", " << test_case.is_deleted + << ")"); + + PasswordForm form = + test_case.is_http ? CreateTestHTTPForm() : CreateTestHTTPSForm(); + form.blacklisted_by_user = test_case.is_blacklisted; + if (test_case.is_http && test_case.is_blacklisted) { + EXPECT_CALL(client(), IsHSTSActiveForHost(form.origin)) + .WillOnce(Return(test_case.is_hsts)); + } + + EXPECT_CALL(store(), RemoveLogin(form)).Times(test_case.is_deleted); + cleaner.OnGetPasswordStoreResults(MakeResults({form})); + } +} + +TEST_F(ObsoleteHttpCleanerTest, TestAutofillableDeletion) { + struct TestCase { + bool is_hsts; + bool same_host; + bool same_user; + bool same_pass; + bool is_deleted; + }; + + constexpr static TestCase cases[] = { + {true, true, true, true, true}, {true, true, true, false, false}, + {true, true, false, true, false}, {true, true, false, false, false}, + {true, false, true, true, false}, {true, false, true, false, false}, + {true, false, false, true, false}, {true, false, false, false, false}, + {false, true, true, true, false}, {false, true, true, false, false}, + {false, true, false, true, false}, {false, true, false, false, false}, + {false, false, true, true, false}, {false, false, true, false, false}, + {false, false, false, true, false}, {false, false, false, false, false}, + }; + + ObsoleteHttpCleaner cleaner(&client()); + for (const auto& test_case : cases) { + SCOPED_TRACE(testing::Message() + << std::boolalpha + << "(is_hsts, same_host, same_user, same_pass, is_deleted): (" + << test_case.is_hsts << ", " << test_case.same_host << ", " + << test_case.same_user << ", " << test_case.same_pass << ", " + << test_case.is_deleted << ")"); + + PasswordForm http_form = CreateTestHTTPForm(); + PasswordForm https_form = CreateTestHTTPSForm(); + + if (!test_case.same_host) { + GURL::Replacements rep; + rep.SetHostStr("a-totally-different-host"); + http_form.origin = http_form.origin.ReplaceComponents(rep); + } + + if (!test_case.same_user) { + http_form.username_value = + https_form.username_value + base::ASCIIToUTF16("-different"); + } + + if (!test_case.same_pass) { + http_form.password_value = + https_form.password_value + base::ASCIIToUTF16("-different"); + } + + EXPECT_CALL(client(), IsHSTSActiveForHost(https_form.origin)) + .WillOnce(Return(test_case.is_hsts)); + EXPECT_CALL(store(), RemoveLogin(http_form)).Times(test_case.is_deleted); + cleaner.OnGetPasswordStoreResults(MakeResults({http_form, https_form})); + } +} + +TEST_F(ObsoleteHttpCleanerTest, TestSiteStatsDeletion) { + struct TestCase { + bool is_http; + bool is_hsts; + bool is_deleted; + }; + + constexpr static TestCase cases[] = { + {true, true, true}, + {true, false, false}, + {false, true, false}, + {false, false, false}, + }; + + ObsoleteHttpCleaner cleaner(&client()); + for (const auto& test_case : cases) { + SCOPED_TRACE(testing::Message() + << std::boolalpha << "(is_http, is_hsts, is_deleted): (" + << test_case.is_http << ", " << test_case.is_hsts << ", " + << test_case.is_deleted << ")"); + + InteractionsStats stats = + test_case.is_http ? CreateTestHTTPStats() : CreateTestHTTPSStats(); + if (test_case.is_http) { + EXPECT_CALL(client(), IsHSTSActiveForHost(stats.origin_domain)) + .WillOnce(Return(test_case.is_hsts)); + } + + EXPECT_CALL(store(), RemoveSiteStatsImpl(stats.origin_domain)) + .Times(test_case.is_deleted); + cleaner.OnGetSiteStatistics({stats}); + base::RunLoop().RunUntilIdle(); + } +} + +} // namespace password_manager
diff --git a/components/password_manager/core/browser/password_autofill_manager.cc b/components/password_manager/core/browser/password_autofill_manager.cc index 9033503..306f206 100644 --- a/components/password_manager/core/browser/password_autofill_manager.cc +++ b/components/password_manager/core/browser/password_autofill_manager.cc
@@ -72,6 +72,7 @@ const base::string16& field_contents, const std::string& signon_realm, bool show_all, + bool is_password_field, std::vector<autofill::Suggestion>* suggestions) { base::string16 lower_suggestion = base::i18n::ToLower(field_suggestion); base::string16 lower_contents = base::i18n::ToLower(field_contents); @@ -83,7 +84,9 @@ lower_suggestion, lower_contents, true)) { autofill::Suggestion suggestion(ReplaceEmptyUsername(field_suggestion)); suggestion.label = GetHumanReadableRealm(signon_realm); - suggestion.frontend_id = autofill::POPUP_ITEM_ID_PASSWORD_ENTRY; + suggestion.frontend_id = is_password_field + ? autofill::POPUP_ITEM_ID_PASSWORD_ENTRY + : autofill::POPUP_ITEM_ID_USERNAME_ENTRY; suggestion.match = prefix_matched_suggestion ? autofill::Suggestion::PREFIX_MATCH : autofill::Suggestion::SUBSTRING_MATCH; @@ -97,19 +100,23 @@ void GetSuggestions(const autofill::PasswordFormFillData& fill_data, const base::string16& current_username, std::vector<autofill::Suggestion>* suggestions, - bool show_all) { + bool show_all, + bool is_password_field) { AppendSuggestionIfMatching(fill_data.username_field.value, current_username, - fill_data.preferred_realm, show_all, suggestions); + fill_data.preferred_realm, show_all, + is_password_field, suggestions); for (const auto& login : fill_data.additional_logins) { AppendSuggestionIfMatching(login.first, current_username, - login.second.realm, show_all, suggestions); + login.second.realm, show_all, is_password_field, + suggestions); } for (const auto& usernames : fill_data.other_possible_usernames) { for (size_t i = 0; i < usernames.second.size(); ++i) { AppendSuggestionIfMatching(usernames.second[i], current_username, - usernames.first.realm, show_all, suggestions); + usernames.first.realm, show_all, + is_password_field, suggestions); } } @@ -194,7 +201,8 @@ return; } GetSuggestions(fill_data_it->second, typed_username, &suggestions, - options & autofill::SHOW_ALL); + (options & autofill::SHOW_ALL) != 0, + (options & autofill::IS_PASSWORD_FIELD) != 0); form_data_key_ = key;
diff --git a/components/password_manager/core/browser/password_autofill_manager_unittest.cc b/components/password_manager/core/browser/password_autofill_manager_unittest.cc index e8de647..80926358 100644 --- a/components/password_manager/core/browser/password_autofill_manager_unittest.cc +++ b/components/password_manager/core/browser/password_autofill_manager_unittest.cc
@@ -186,38 +186,48 @@ // Test that the popup is marked as visible after recieving password // suggestions. TEST_F(PasswordAutofillManagerTest, ExternalDelegatePasswordSuggestions) { - std::unique_ptr<TestPasswordManagerClient> client( - new TestPasswordManagerClient); - std::unique_ptr<MockAutofillClient> autofill_client(new MockAutofillClient); - InitializePasswordAutofillManager(client.get(), autofill_client.get()); + for (bool is_suggestion_on_password_field : {false, true}) { + std::unique_ptr<TestPasswordManagerClient> client( + new TestPasswordManagerClient); + std::unique_ptr<MockAutofillClient> autofill_client(new MockAutofillClient); + InitializePasswordAutofillManager(client.get(), autofill_client.get()); - gfx::RectF element_bounds; - autofill::PasswordFormFillData data; - data.username_field.value = test_username_; - data.password_field.value = test_password_; - data.preferred_realm = "http://foo.com/"; - int dummy_key = 0; - password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data); + gfx::RectF element_bounds; + autofill::PasswordFormFillData data; + data.username_field.value = test_username_; + data.password_field.value = test_password_; + data.preferred_realm = "http://foo.com/"; + int dummy_key = 0; + password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data); - EXPECT_CALL(*client->mock_driver(), - FillSuggestion(test_username_, test_password_)); + EXPECT_CALL(*client->mock_driver(), + FillSuggestion(test_username_, test_password_)); - // The enums must be cast to ints to prevent compile errors on linux_rel. - EXPECT_CALL(*autofill_client, - ShowAutofillPopup( - _, - _, - SuggestionVectorIdsAre(testing::ElementsAre( - autofill::POPUP_ITEM_ID_PASSWORD_ENTRY)), - _)); - password_autofill_manager_->OnShowPasswordSuggestions( - dummy_key, base::i18n::RIGHT_TO_LEFT, base::string16(), false, - element_bounds); + // The enums must be cast to ints to prevent compile errors on linux_rel. + auto suggestion_ids_matcher = + is_suggestion_on_password_field + ? SuggestionVectorIdsAre( + testing::ElementsAre(autofill::POPUP_ITEM_ID_TITLE, + autofill::POPUP_ITEM_ID_PASSWORD_ENTRY)) + : SuggestionVectorIdsAre( + testing::ElementsAre(autofill::POPUP_ITEM_ID_USERNAME_ENTRY)); + EXPECT_CALL(*autofill_client, + ShowAutofillPopup(_, _, suggestion_ids_matcher, _)); - // Accepting a suggestion should trigger a call to hide the popup. - EXPECT_CALL(*autofill_client, HideAutofillPopup()); - password_autofill_manager_->DidAcceptSuggestion( - test_username_, autofill::POPUP_ITEM_ID_PASSWORD_ENTRY, 1); + int show_suggestion_options = + is_suggestion_on_password_field ? autofill::IS_PASSWORD_FIELD : 0; + password_autofill_manager_->OnShowPasswordSuggestions( + dummy_key, base::i18n::RIGHT_TO_LEFT, base::string16(), + show_suggestion_options, element_bounds); + + // Accepting a suggestion should trigger a call to hide the popup. + EXPECT_CALL(*autofill_client, HideAutofillPopup()); + password_autofill_manager_->DidAcceptSuggestion( + test_username_, is_suggestion_on_password_field + ? autofill::POPUP_ITEM_ID_PASSWORD_ENTRY + : autofill::POPUP_ITEM_ID_USERNAME_ENTRY, + 1); + } } // Test that OnShowPasswordSuggestions correctly matches the given FormFieldData
diff --git a/components/password_manager/core/browser/password_manager_client.cc b/components/password_manager/core/browser/password_manager_client.cc index 2c51dc6..fc790141 100644 --- a/components/password_manager/core/browser/password_manager_client.cc +++ b/components/password_manager/core/browser/password_manager_client.cc
@@ -19,6 +19,10 @@ return true; } +bool PasswordManagerClient::IsHSTSActiveForHost(const GURL& origin) const { + return false; +} + bool PasswordManagerClient::OnCredentialManagerUsed() { return true; }
diff --git a/components/password_manager/core/browser/password_manager_client.h b/components/password_manager/core/browser/password_manager_client.h index 7146770..f4ac3aca 100644 --- a/components/password_manager/core/browser/password_manager_client.h +++ b/components/password_manager/core/browser/password_manager_client.h
@@ -19,6 +19,8 @@ class AutofillManager; } +class GURL; + namespace password_manager { class LogManager; @@ -63,6 +65,10 @@ // password manager is disabled, or in the presence of SSL errors on a page. virtual bool IsFillingEnabledForCurrentPage() const; + // Checks whether HTTP Strict Transport Security (HSTS) is active for the host + // of the given origin. + virtual bool IsHSTSActiveForHost(const GURL& origin) const; + // Checks if the Credential Manager API is allowed to run on the page. It's // not allowed while prerendering and the pre-rendered WebContents will be // destroyed in this case.
diff --git a/components/payments_strings.grdp b/components/payments_strings.grdp new file mode 100644 index 0000000..446ac6c --- /dev/null +++ b/components/payments_strings.grdp
@@ -0,0 +1,194 @@ +<?xml version="1.0" encoding="utf-8"?> +<grit-part> + + <message name="IDS_PAYMENTS_NAME_FIELD_IN_CONTACT_DETAILS" desc="The label for text input field containing the full name of a person. [CHAR-LIMIT=32]" formatter_data="android_java"> + Name + </message> + <message name="IDS_PAYMENTS_SAVE_CARD_TO_DEVICE_CHECKBOX" desc="The label for the checkbox that enables the user to save a credit card to their device, for example, on their phone." formatter_data="android_java"> + Save this card to this device + </message> + <message name="IDS_PAYMENTS_ACCEPTED_CARDS_LABEL" desc="The title for the section that displays the credit card types that the merchant accepts." formatter_data="android_java"> + Cards accepted + </message> + <message name="IDS_PAYMENTS_METHOD_OF_PAYMENT_LABEL" desc="The title for the section that lets the user select the method of payment." formatter_data="android_java"> + Payment + </message> + <message name="IDS_PAYMENTS_CONTACT_DETAILS_LABEL" desc="The title for the section that lets the user select how they can be contacted." formatter_data="android_java"> + Contact info + </message> + <message name="IDS_PAYMENTS_ADD_CONTACT_DETAILS_LABEL" desc="The title of the dialog for user to add new contact information, such as the user's full name, an email address or a phone number." formatter_data="android_java"> + Add contact info + </message> + <message name="IDS_PAYMENTS_EDIT_CONTACT_DETAILS_LABEL" desc="The title of the dialog for user to edit their contact information, such as the user's full name, an email address or a phone number." formatter_data="android_java"> + Edit contact info + </message> + <message name="IDS_PAYMENTS_ADD_CARD" desc="The title of the dialog for user to add new payment card." formatter_data="android_java"> + Add card + </message> + <message name="IDS_PAYMENTS_BILLING_ADDRESS_REQUIRED" desc="The label to indicate billing address is required for payment card." formatter_data="android_java"> + Billing address required + </message> + <message name="IDS_PAYMENTS_ADD_BILLING_ADDRESS" desc="The title of the dialog for user to add billing address to payment card." formatter_data="android_java"> + Add billing address + </message> + <message name="IDS_PAYMENTS_NAME_ON_CARD_REQUIRED" desc="The label to indicate name on card is required for payment card." formatter_data="android_java"> + Name on card required + </message> + <message name="IDS_PAYMENTS_ADD_NAME_ON_CARD" desc="The title of the dialog for user to add name on card to payment card." formatter_data="android_java"> + Add name on card + </message> + <message name="IDS_PAYMENTS_CARD_NUMBER_INVALID" desc="The label to indicate payment card number is invalid." formatter_data="android_java"> + Card number invalid + </message> + <message name="IDS_PAYMENTS_ADD_VALID_CARD_NUMBER" desc="The title of the dialog for user to add valid payment card number." formatter_data="android_java"> + Add valid card number + </message> + <message name="IDS_PAYMENTS_MORE_INFORMATION_REQUIRED" desc="The label to indicate more information is required for payment card or shipping address or contact info." formatter_data="android_java"> + More information required + </message> + <message name="IDS_PAYMENTS_ADD_MORE_INFORMATION" desc="The title of the dialog for user to add more information to payment card or shipping address or contact info." formatter_data="android_java"> + Add more information + </message> + <message name="IDS_PAYMENTS_EDIT_CARD" desc="The title of the dialog for user to edit payment card." formatter_data="android_java"> + Edit card + </message> + <message name="IDS_PAYMENTS_CREDIT_CARD_EXPIRATION_DATE_ABBR" desc="Abbreviated label for credit card expiration date. [CHAR-LIMIT=32]" formatter_data="android_java"> + Exp: <ph name="EXPIRATION_MONTH">%1$s<ex>06</ex></ph>/<ph name="EXPIRATION_YEAR">%2$s<ex>17</ex></ph> + </message> + <message name="IDS_PAYMENTS_PHONE_NUMBER_REQUIRED" desc="The label to indicate phone number is required in the shipping address or contact info. This phone number can be used, for example, if there's a problem with shipping a package to its destination." formatter_data="android_java"> + Phone number required + </message> + <message name="IDS_PAYMENTS_ADD_PHONE_NUMBER" desc="The title of the dialog for user to add phone number to the shipping address or contact info. This phone number can be used, for example, if there's a problem with shipping a package to its destination." formatter_data="android_java"> + Add phone number + </message> + <message name="IDS_PAYMENTS_RECIPIENT_REQUIRED" desc="The label to indicate recipient is required in the shipping address. The recipient could be a person or institute name identifies the receiver of the shipping package." formatter_data="android_java"> + Recipient required + </message> + <message name="IDS_PAYMENTS_ADD_RECIPIENT" desc="The title of the dialog for user to add recipient in the shipping address. The recipient could be a person or institute name identifies the receiver of the shipping package." formatter_data="android_java"> + Add recipient + </message> + <message name="IDS_PAYMENTS_INVALID_ADDRESS" desc="The label to indicate the shipping address is invalid. For example, missing state or city name." formatter_data="android_java"> + Invalid address + </message> + <message name="IDS_PAYMENTS_ADD_VALID_ADDRESS" desc="The title of the dialog for user to add valid shipping address. For example, missing state or city name." formatter_data="android_java"> + Add valid address + </message> + <message name="IDS_PAYMENTS_EMAIL_REQUIRED" desc="The label to indicate email is required for the contact details. This email can be used to contact the payer." formatter_data="android_java"> + Email required + </message> + <message name="IDS_PAYMENTS_ADD_EMAIL" desc="The title of the dialog for user to add email to the contact details. This email can be used to contact the payer." formatter_data="android_java"> + Add email + </message> + <message name="IDS_PAYMENTS_NAME_REQUIRED" desc="The label to indicate name is required for the contact details. This name could be a person or institute name of the payer." formatter_data="android_java"> + Name required + </message> + <message name="IDS_PAYMENTS_ADD_NAME" desc="The title of the dialog for user to add name to the contact details. This name could be a person or institute name of the payer." formatter_data="android_java"> + Add name + </message> + <message name="IDS_PAYMENTS_ORDER_SUMMARY_LABEL" desc="The title of the section that shows the summary of the order, including names and prices of individual line items, i.e. the bill." formatter_data="android_java"> + Order summary + </message> + <message name="IDS_PAYMENTS_EDIT_BUTTON" desc="The label for the button that lets the user edit their payment options." formatter_data="android_java"> + Edit + </message> + <message name="IDS_PAYMENTS_PAY_BUTTON" desc="The label for the button that finishes the payment process." formatter_data="android_java"> + Pay + </message> + <message name="IDS_PAYMENTS_LOADING_MESSAGE" desc="The text that informs the user that payment information is being loaded up." formatter_data="android_java"> + Loading + </message> + <message name="IDS_PAYMENTS_ERROR_MESSAGE" desc="The text that informs the user that there is error in verifying and charging the payment." formatter_data="android_java"> + There was an error processing your order. Please check your account and try again. + </message> + <message name="IDS_PAYMENTS_REQUIRED_FIELD_MESSAGE" desc="The text that informs the user that '*' character indicates an input field that is required. The '*' character should not be changed." formatter_data="android_java"> + * indicates required field + </message> + <message name="IDS_PAYMENTS_FIELD_REQUIRED_VALIDATION_MESSAGE" desc="The text that informs the user that an input field is required." formatter_data="android_java"> + Required field + </message> + <message name="IDS_PAYMENTS_PHONE_INVALID_VALIDATION_MESSAGE" desc="The text that informs the user that the phone number they have entered is not valid." formatter_data="android_java"> + Invalid phone number + </message> + <message name="IDS_PAYMENTS_EMAIL_INVALID_VALIDATION_MESSAGE" desc="The text that informs the user that the email address they have entered is not valid." formatter_data="android_java"> + Invalid email address + </message> + <message name="IDS_PAYMENTS_CARD_NUMBER_INVALID_VALIDATION_MESSAGE" desc="The text that informs the user that the credit card number they have entered is not valid." formatter_data="android_java"> + Invalid card number + </message> + <message name="IDS_PAYMENTS_CARD_EXPIRATION_INVALID_VALIDATION_MESSAGE" desc="The text that informs the user that the credit card expiration date they have entered is not valid." formatter_data="android_java"> + Invalid expiration date + </message> + <message name="IDS_PAYMENTS_ADD_CONTACT" desc="Text on a button that lets a user add new contact details, like the user's full name, an email address or a phone number." formatter_data="android_java"> + Add contact info + </message> + <message name="IDS_PAYMENTS_CHECKING_OPTION" desc="Text explaining that the option the user selected is being checked and verified." formatter_data="android_java"> + Checking + </message> + <message name="IDS_PAYMENTS_UPDATED_LABEL" desc="The text that informs the user that the total value of their cart has been updated." formatter_data="android_java"> + Updated + </message> + <message name="IDS_PAYMENTS_CARD_AND_ADDRESS_SETTINGS" desc="Label of the section containing the link to go to the settings page for card and address options." formatter_data="android_java"> + You can manage cards and addresses in <ph name="BEGIN_LINK"><link></ph>Settings<ph name="END_LINK"></link></ph>. + </message> + <message name="IDS_PAYMENTS_CARD_AND_ADDRESS_SETTINGS_SIGNED_IN" desc="Label of the section containing the origin description and the link to go to the settings page for card and address options. This label is used when the user is signed in." formatter_data="android_java"> + Card and address options are from your Google Account (<ph name="ACCOUNT_EMAIL">%1$s<ex>johndoe@gmail.com</ex></ph>) and Chrome. You can manage these in <ph name="BEGIN_LINK"><link></ph>Settings<ph name="END_LINK"></link></ph>. + </message> + <message name="IDS_PAYMENTS_CARD_AND_ADDRESS_SETTINGS_SIGNED_OUT" desc="Label of the section containing the origin description and the link to go to the settings page for card and address options. This label is used when the user is not signed in." formatter_data="android_java"> + Card and address options are from Chrome. You can manage these in <ph name="BEGIN_LINK"><link></ph>Settings<ph name="END_LINK"></link></ph>. + </message> + + <!-- Shipping address in web payments API --> + <message name="IDS_PAYMENTS_SHIPPING_SUMMARY_LABEL" desc="The title for the section of shipping information. Shipping is typically used for packages." formatter_data="android_java"> + Shipping + </message> + <message name="IDS_PAYMENTS_SHIPPING_ADDRESS_LABEL" desc="The title for the section that lets the user select the address where the product should be shipped. Shipping is typically used for packages." formatter_data="android_java"> + Shipping address + </message> + <message name="IDS_PAYMENTS_SHIPPING_OPTION_LABEL" desc="The title for the section that lets the user select how the product should be shipped. Shipping is typically used for packages." formatter_data="android_java"> + Shipping option + </message> + <message name="IDS_PAYMENTS_SELECT_SHIPPING_ADDRESS_FOR_SHIPPING_METHODS" desc="Text implying that a user needs to pick a shipping address to see the shipping methods. Shipping is typically used for packages." formatter_data="android_java"> + Select a shipping address to check shipping methods and requirements. + </message> + <message name="IDS_PAYMENTS_UNSUPPORTED_SHIPPING_ADDRESS" desc="Text implying that a user needs to pick a different shipping address, because the currently selected address is not supported. Shipping is typically used for packages." formatter_data="android_java"> + Unsupported shipping address. Select a different address. + </message> + + <!-- Delivery address in web payments API --> + <message name="IDS_PAYMENTS_DELIVERY_SUMMARY_LABEL" desc="The title for the section of delivery information. Delivery is commonly faster than shipping. For example, it might be used for food delivery." formatter_data="android_java"> + Delivery + </message> + <message name="IDS_PAYMENTS_DELIVERY_ADDRESS_LABEL" desc="The title for the section that lets the user select the address where the product should be delivered. Delivery is commonly faster than shipping. For example, it might be used for food delivery." formatter_data="android_java"> + Delivery address + </message> + <message name="IDS_PAYMENTS_DELIVERY_OPTION_LABEL" desc="The title for the section that lets the user select how the product should be delivered. Delivery is commonly faster than shipping. For example, it might be used for food delivery." formatter_data="android_java"> + Delivery option + </message> + <message name="IDS_PAYMENTS_SELECT_DELIVERY_ADDRESS_FOR_DELIVERY_METHODS" desc="Text implying that a user needs to pick a delivery address to see the delivery methods. Delivery is commonly faster than shipping. For example, it might be used for food delivery." formatter_data="android_java"> + Select a delivery address to check delivery methods and requirements. + </message> + <message name="IDS_PAYMENTS_UNSUPPORTED_DELIVERY_ADDRESS" desc="Text implying that a user needs to pick a different delivery address, because the currently selected address is not supported. Delivery is commonly faster than shipping. For example, it might be used for food delivery." formatter_data="android_java"> + Unsupported delivery address. Select a different address. + </message> + + <!-- Pickup address in web payments API --> + <message name="IDS_PAYMENTS_PICKUP_SUMMARY_LABEL" desc="The title for the section of pickup information. For example, this could be the address for laundry pickup." formatter_data="android_java"> + Pickup + </message> + <message name="IDS_PAYMENTS_PICKUP_ADDRESS_LABEL" desc="The title for the section that lets the user select the address where their item should be picked up. For example, this item could be laundry to be cleaned." formatter_data="android_java"> + Pickup address + </message> + <message name="IDS_PAYMENTS_PICKUP_OPTION_LABEL" desc="The title for the section that lets the user select how their item should be picked up. This item can be laundry to be cleaned, for example." formatter_data="android_java"> + Pickup option + </message> + <message name="IDS_PAYMENTS_SELECT_PICKUP_ADDRESS_FOR_PICKUP_METHODS" desc="Text implying that a user needs to choose a pickup address to see the pickup methods. For example, this could be the address for laundry pickup." formatter_data="android_java"> + Select a pickup address to check pickup methods and requirements. + </message> + <message name="IDS_PAYMENTS_UNSUPPORTED_PICKUP_ADDRESS" desc="Text implying that a user needs to choose a different pickup address, because the currently selected address is not supported. This address can be used, for example, for laundry pickup." formatter_data="android_java"> + Unsupported pickup address. Select a different address. + </message> + <message name="IDS_PAYMENTS_ANDROID_APP_ERROR" desc="Error message that is shown when an Android payment application fails to start." formatter_data="android_java"> + Unable to launch payment app. + </message> + +</grit-part>
diff --git a/components/policy/core/browser/cloud/message_util.cc b/components/policy/core/browser/cloud/message_util.cc index 2292b5b7..3c12f9e 100644 --- a/components/policy/core/browser/cloud/message_util.cc +++ b/components/policy/core/browser/cloud/message_util.cc
@@ -48,6 +48,9 @@ return IDS_POLICY_DM_STATUS_SERVICE_POLICY_NOT_FOUND; case DM_STATUS_CANNOT_SIGN_REQUEST: return IDS_POLICY_DM_STATUS_CANNOT_SIGN_REQUEST; + case DM_STATUS_SERVICE_ARC_DISABLED: + // This error is never shown on the UI. + return IDS_POLICY_DM_STATUS_UNKNOWN_ERROR; } NOTREACHED() << "Unhandled DM status " << status; return IDS_POLICY_DM_STATUS_UNKNOWN_ERROR;
diff --git a/components/policy/core/common/cloud/cloud_policy_constants.cc b/components/policy/core/common/cloud/cloud_policy_constants.cc index f272a72..d37a2e3 100644 --- a/components/policy/core/common/cloud/cloud_policy_constants.cc +++ b/components/policy/core/common/cloud/cloud_policy_constants.cc
@@ -49,6 +49,10 @@ const char kValueRequestGcmIdUpdate[] = "gcm_id_update"; const char kValueRequestCheckAndroidManagement[] = "check_android_management"; const char kValueRequestCertBasedRegister[] = "certificate_based_register"; +const char kValueRequestActiveDirectoryEnrollPlayUser[] = + "active_directory_enroll_play_user"; +const char kValueRequestActiveDirectoryPlayActivity[] = + "active_directory_play_activity"; const char kChromeDevicePolicyType[] = "google/chromeos/device"; #if defined(OS_CHROMEOS)
diff --git a/components/policy/core/common/cloud/cloud_policy_constants.h b/components/policy/core/common/cloud/cloud_policy_constants.h index 7329fd2..25a41103 100644 --- a/components/policy/core/common/cloud/cloud_policy_constants.h +++ b/components/policy/core/common/cloud/cloud_policy_constants.h
@@ -43,6 +43,8 @@ POLICY_EXPORT extern const char kValueRequestGcmIdUpdate[]; POLICY_EXPORT extern const char kValueRequestCheckAndroidManagement[]; POLICY_EXPORT extern const char kValueRequestCertBasedRegister[]; +POLICY_EXPORT extern const char kValueRequestActiveDirectoryEnrollPlayUser[]; +POLICY_EXPORT extern const char kValueRequestActiveDirectoryPlayActivity[]; // Policy type strings for the policy_type field in PolicyFetchRequest. POLICY_EXPORT extern const char kChromeDevicePolicyType[]; @@ -109,6 +111,8 @@ DM_STATUS_CANNOT_SIGN_REQUEST = 15, // Service error: Policy not found. Error code defined by the DM folks. DM_STATUS_SERVICE_POLICY_NOT_FOUND = 902, + // Service error: ARC is not enabled on this domain. + DM_STATUS_SERVICE_ARC_DISABLED = 904, }; // List of modes that the device can be locked into.
diff --git a/components/policy/core/common/cloud/cloud_policy_refresh_scheduler.cc b/components/policy/core/common/cloud/cloud_policy_refresh_scheduler.cc index c01eb9b..fde9ed3f 100644 --- a/components/policy/core/common/cloud/cloud_policy_refresh_scheduler.cc +++ b/components/policy/core/common/cloud/cloud_policy_refresh_scheduler.cc
@@ -281,6 +281,9 @@ // Need a re-registration, no use in retrying. CancelRefresh(); return; + case DM_STATUS_SERVICE_ARC_DISABLED: + // This doesn't occur during policy refresh, don't change the schedule. + return; } NOTREACHED() << "Invalid client status " << client_->status();
diff --git a/components/policy/core/common/cloud/device_management_service.cc b/components/policy/core/common/cloud/device_management_service.cc index 30e26c3..66a758d 100644 --- a/components/policy/core/common/cloud/device_management_service.cc +++ b/components/policy/core/common/cloud/device_management_service.cc
@@ -54,6 +54,7 @@ const int kServiceUnavailable = 503; const int kPolicyNotFound = 902; const int kDeprovisioned = 903; +const int kArcDisabled = 904; // Delay after first unsuccessful upload attempt. After each additional failure, // the delay increases exponentially. Can be changed for testing to prevent @@ -150,6 +151,10 @@ return dm_protocol::kValueRequestCheckAndroidManagement; case DeviceManagementRequestJob::TYPE_CERT_BASED_REGISTRATION: return dm_protocol::kValueRequestCertBasedRegister; + case DeviceManagementRequestJob::TYPE_ACTIVE_DIRECTORY_ENROLL_PLAY_USER: + return dm_protocol::kValueRequestActiveDirectoryEnrollPlayUser; + case DeviceManagementRequestJob::TYPE_ACTIVE_DIRECTORY_PLAY_ACTIVITY: + return dm_protocol::kValueRequestActiveDirectoryPlayActivity; } NOTREACHED() << "Invalid job type " << type; return ""; @@ -345,6 +350,9 @@ case kDeviceIdConflict: ReportError(DM_STATUS_SERVICE_DEVICE_ID_CONFLICT); return; + case kArcDisabled: + ReportError(DM_STATUS_SERVICE_ARC_DISABLED); + return; default: // Handle all unknown 5xx HTTP error codes as temporary and any other // unknown error as one that needs more time to recover.
diff --git a/components/policy/core/common/cloud/device_management_service.h b/components/policy/core/common/cloud/device_management_service.h index ddb675c..c19ccc4 100644 --- a/components/policy/core/common/cloud/device_management_service.h +++ b/components/policy/core/common/cloud/device_management_service.h
@@ -57,6 +57,8 @@ TYPE_GCM_ID_UPDATE = 11, TYPE_ANDROID_MANAGEMENT_CHECK = 12, TYPE_CERT_BASED_REGISTRATION = 13, + TYPE_ACTIVE_DIRECTORY_ENROLL_PLAY_USER = 14, + TYPE_ACTIVE_DIRECTORY_PLAY_ACTIVITY = 15, }; typedef base::Callback<
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index d4e26e4..134ba1d 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -139,7 +139,7 @@ # persistent IDs for all fields (but not for groups!) are needed. These are # specified by the 'id' keys of each policy. NEVER CHANGE EXISTING IDs, # because doing so would break the deployed wire format! -# For your editing convenience: highest ID currently used: 363 +# For your editing convenience: highest ID currently used: 365 # And don't forget to also update the EnterprisePolicies enum of # histograms.xml. # @@ -9545,6 +9545,48 @@ If the device wallpaper policy is left not set, it's the user's wallpaper policy to decide what to show if the user's wallpaper policy is set.''', }, + { + 'name': 'DeviceLoginScreenLocales', + 'type': 'list', + 'schema': { + 'type': 'array', + 'items': { 'type': 'string' }, + }, + 'supported_on': ['chrome_os:58-'], + 'device_only': True, + 'features': { + 'dynamic_refresh': False, + }, + 'example_value': [ "en-US" ], + 'max_size': 16777216, + 'id': 364, + 'caption': '''Device sign-in screen locale''', + 'tags': [], + 'desc': '''Configures the locale which is enforced on the <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> sign-in screen. + + If this policy is set, the sign-in screen will always be displayed in the locale which is given by the first value of this policy (the policy is defined as a list for forward compatibility). If this policy is not set or is set to an empty list, the sign-in screen will be displayed in the locale of the last user session. If this policy is set to a value which is not a valid locale, the sign-in screen will be displayed in a fallback locale (currently, en-US).''' + }, + { + 'name': 'DeviceLoginScreenInputMethods', + 'type': 'list', + 'schema': { + 'type': 'array', + 'items': { 'type': 'string' }, + }, + 'supported_on': ['chrome_os:58-'], + 'device_only': True, + 'features': { + 'dynamic_refresh': True, + }, + 'example_value': [ "xkb:us::en", "xkb:ch::ger" ], + 'max_size': 16777216, + 'id': 365, + 'caption': '''Device sign-in screen keyboard layouts''', + 'tags': [], + 'desc': '''Configures which keyboard layouts are allowed on the <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> sign-in screen. + + If this policy is set to a list of input method identifiers, the given input methods will be available on the sign-in screen. The first given input method will be preselected. While a user pod is focused on the sign-in screen, the user's least recently used input method will be available in addition to the input methods given by this policy. If this policy is not set, the input methods on the sign-in screen will be derived from the locale in which the sign-in screen is displayed. Values which are not valid input method identifiers will be ignored.''', + }, ], 'messages': { # Messages that are not associated to any policies.
diff --git a/components/printing/renderer/print_web_view_helper.cc b/components/printing/renderer/print_web_view_helper.cc index 00a3863..9d9a87c 100644 --- a/components/printing/renderer/print_web_view_helper.cc +++ b/components/printing/renderer/print_web_view_helper.cc
@@ -937,7 +937,8 @@ scripting_throttler_.IsAllowed(frame); } -void PrintWebViewHelper::DidStartProvisionalLoad() { +void PrintWebViewHelper::DidStartProvisionalLoad( + blink::WebDataSource* data_source) { is_loading_ = true; }
diff --git a/components/printing/renderer/print_web_view_helper.h b/components/printing/renderer/print_web_view_helper.h index 7c1fdbd..d979333 100644 --- a/components/printing/renderer/print_web_view_helper.h +++ b/components/printing/renderer/print_web_view_helper.h
@@ -171,7 +171,7 @@ // RenderFrameObserver implementation. void OnDestruct() override; - void DidStartProvisionalLoad() override; + void DidStartProvisionalLoad(blink::WebDataSource* data_source) override; void DidFailProvisionalLoad(const blink::WebURLError& error) override; void DidFinishLoad() override; void ScriptedPrint(bool user_initiated) override;
diff --git a/components/safe_browsing_db/database_manager.h b/components/safe_browsing_db/database_manager.h index 9399f78..01ae7ca 100644 --- a/components/safe_browsing_db/database_manager.h +++ b/components/safe_browsing_db/database_manager.h
@@ -46,7 +46,8 @@ virtual void OnCheckApiBlacklistUrlResult(const GURL& url, const ThreatMetadata& metadata) {} - // Called when the result of checking a browse URL is known. + // Called when the result of checking a browse URL is known or the result of + // checking the URL for subresource filter is known. virtual void OnCheckBrowseUrlResult(const GURL& url, SBThreatType threat_type, const ThreatMetadata& metadata) {} @@ -117,6 +118,15 @@ // result when it is ready. virtual bool CheckBrowseUrl(const GURL& url, Client* client) = 0; + // Called on the IO thread to check if the given url belongs to the + // subresource filter list. If the url doesn't belong to the list, the check + // happens synchronously, otherwise it returns false, and "client" is called + // asynchronously with the result when it is ready. + // Currently supported only on desktop. Returns TRUE if the list is not yet + // available. + virtual bool CheckUrlForSubresourceFilter(const GURL& url, + Client* client) = 0; + // Check if the prefix for |url| is in safebrowsing download add lists. // Result will be passed to callback in |client|. virtual bool CheckDownloadUrl(const std::vector<GURL>& url_chain,
diff --git a/components/safe_browsing_db/remote_database_manager.cc b/components/safe_browsing_db/remote_database_manager.cc index 256c511..2def386 100644 --- a/components/safe_browsing_db/remote_database_manager.cc +++ b/components/safe_browsing_db/remote_database_manager.cc
@@ -222,6 +222,13 @@ return true; } +bool RemoteSafeBrowsingDatabaseManager::CheckUrlForSubresourceFilter( + const GURL& url, + Client* client) { + NOTREACHED(); + return false; +} + bool RemoteSafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) { NOTREACHED(); return true;
diff --git a/components/safe_browsing_db/remote_database_manager.h b/components/safe_browsing_db/remote_database_manager.h index 3327081..7f8ff4e 100644 --- a/components/safe_browsing_db/remote_database_manager.h +++ b/components/safe_browsing_db/remote_database_manager.h
@@ -48,6 +48,7 @@ bool CheckExtensionIDs(const std::set<std::string>& extension_ids, Client* client) override; bool CheckResourceUrl(const GURL& url, Client* client) override; + bool CheckUrlForSubresourceFilter(const GURL& url, Client* client) override; bool MatchCsdWhitelistUrl(const GURL& url) override; bool MatchDownloadWhitelistString(const std::string& str) override; bool MatchDownloadWhitelistUrl(const GURL& url) override;
diff --git a/components/safe_browsing_db/safebrowsing.proto b/components/safe_browsing_db/safebrowsing.proto index 42f41d64..fbe1e57 100644 --- a/components/safe_browsing_db/safebrowsing.proto +++ b/components/safe_browsing_db/safebrowsing.proto
@@ -282,6 +282,10 @@ // Client incident threat type. CLIENT_INCIDENT = 10; + + // Patterns to be used for activating the subresource filter. Interstitial + // will not be shown for patterns from this list. + SUBRESOURCE_FILTER = 11; } // Types of platforms.
diff --git a/components/safe_browsing_db/test_database_manager.cc b/components/safe_browsing_db/test_database_manager.cc index b6805ac0..423097e 100644 --- a/components/safe_browsing_db/test_database_manager.cc +++ b/components/safe_browsing_db/test_database_manager.cc
@@ -59,6 +59,13 @@ return true; } +bool TestSafeBrowsingDatabaseManager::CheckUrlForSubresourceFilter( + const GURL& url, + Client* client) { + NOTIMPLEMENTED(); + return true; +} + bool TestSafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) { NOTIMPLEMENTED(); return true;
diff --git a/components/safe_browsing_db/test_database_manager.h b/components/safe_browsing_db/test_database_manager.h index 870807f..c2cd803f 100644 --- a/components/safe_browsing_db/test_database_manager.h +++ b/components/safe_browsing_db/test_database_manager.h
@@ -31,6 +31,7 @@ bool CheckExtensionIDs(const std::set<std::string>& extension_ids, Client* client) override; bool CheckResourceUrl(const GURL& url, Client* client) override; + bool CheckUrlForSubresourceFilter(const GURL& url, Client* client) override; bool MatchCsdWhitelistUrl(const GURL& url) override; bool MatchDownloadWhitelistString(const std::string& str) override; bool MatchDownloadWhitelistUrl(const GURL& url) override;
diff --git a/components/safe_browsing_db/v4_local_database_manager.cc b/components/safe_browsing_db/v4_local_database_manager.cc index 224525982..bed076fa 100644 --- a/components/safe_browsing_db/v4_local_database_manager.cc +++ b/components/safe_browsing_db/v4_local_database_manager.cc
@@ -73,6 +73,8 @@ GetChromeUrlClientIncidentId(), SB_THREAT_TYPE_BLACKLISTED_RESOURCE), ListInfo(kSyncNever, "", GetChromeUrlApiId(), SB_THREAT_TYPE_API_ABUSE), + ListInfo(kSyncOnlyOnChromeBuilds, "UrlSubresourceFilter.store", + GetUrlSubresourceFilterId(), SB_THREAT_TYPE_SUBRESOURCE_FILTER), }); } @@ -87,6 +89,7 @@ case UNWANTED_SOFTWARE: return 1; case API_ABUSE: + case CLIENT_INCIDENT: return 2; default: NOTREACHED() << "Unexpected ThreatType encountered: " @@ -264,6 +267,22 @@ return HandleCheck(std::move(check)); } +bool V4LocalDatabaseManager::CheckUrlForSubresourceFilter(const GURL& url, + Client* client) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + StoresToCheck stores_to_check({GetUrlSubresourceFilterId()}); + if (!AreStoresAvailableNow(stores_to_check) || !CanCheckUrl(url)) { + return true; + } + + std::unique_ptr<PendingCheck> check = base::MakeUnique<PendingCheck>( + client, ClientCallbackType::CHECK_URL_FOR_SUBRESOURCE_FILTER, + stores_to_check, std::vector<GURL>(1, url)); + + return HandleCheck(std::move(check)); +} + bool V4LocalDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) { DCHECK_CURRENTLY_ON(BrowserThread::IO); @@ -457,25 +476,17 @@ DCHECK(v4_database_); const base::TimeTicks before = TimeTicks::Now(); - if (check->client_callback_type == ClientCallbackType::CHECK_BROWSE_URL || - check->client_callback_type == ClientCallbackType::CHECK_DOWNLOAD_URLS || - check->client_callback_type == ClientCallbackType::CHECK_RESOURCE_URL || - check->client_callback_type == ClientCallbackType::CHECK_EXTENSION_IDS || - check->client_callback_type == ClientCallbackType::CHECK_OTHER) { - DCHECK(!check->full_hashes.empty()); + DCHECK(!check->full_hashes.empty()); - full_hash_to_store_and_hash_prefixes->clear(); - for (const auto& full_hash : check->full_hashes) { - StoreAndHashPrefixes matched_store_and_hash_prefixes; - v4_database_->GetStoresMatchingFullHash(full_hash, check->stores_to_check, - &matched_store_and_hash_prefixes); - if (!matched_store_and_hash_prefixes.empty()) { - (*full_hash_to_store_and_hash_prefixes)[full_hash] = - matched_store_and_hash_prefixes; - } + full_hash_to_store_and_hash_prefixes->clear(); + for (const auto& full_hash : check->full_hashes) { + StoreAndHashPrefixes matched_store_and_hash_prefixes; + v4_database_->GetStoresMatchingFullHash(full_hash, check->stores_to_check, + &matched_store_and_hash_prefixes); + if (!matched_store_and_hash_prefixes.empty()) { + (*full_hash_to_store_and_hash_prefixes)[full_hash] = + matched_store_and_hash_prefixes; } - } else { - NOTREACHED() << "Unexpected client_callback_type encountered."; } // TODO(vakh): Only log SafeBrowsing.V4GetPrefixMatches.Time once PVer3 code @@ -659,6 +670,7 @@ switch (check->client_callback_type) { case ClientCallbackType::CHECK_BROWSE_URL: + case ClientCallbackType::CHECK_URL_FOR_SUBRESOURCE_FILTER: DCHECK_EQ(1u, check->urls.size()); check->client->OnCheckBrowseUrlResult( check->urls[0], check->result_threat_type, check->url_metadata); @@ -681,7 +693,6 @@ check->client->OnCheckExtensionsResult(extension_ids); break; } - case ClientCallbackType::CHECK_OTHER: NOTREACHED() << "Unexpected client_callback_type encountered"; }
diff --git a/components/safe_browsing_db/v4_local_database_manager.h b/components/safe_browsing_db/v4_local_database_manager.h index f24e3e9..4cf8160 100644 --- a/components/safe_browsing_db/v4_local_database_manager.h +++ b/components/safe_browsing_db/v4_local_database_manager.h
@@ -52,6 +52,7 @@ bool CheckExtensionIDs(const std::set<FullHash>& extension_ids, Client* client) override; bool CheckResourceUrl(const GURL& url, Client* client) override; + bool CheckUrlForSubresourceFilter(const GURL& url, Client* client) override; bool MatchCsdWhitelistUrl(const GURL& url) override; bool MatchDownloadWhitelistString(const std::string& str) override; bool MatchDownloadWhitelistUrl(const GURL& url) override; @@ -101,10 +102,14 @@ // extension is a unsafe. CHECK_EXTENSION_IDS = 3, + // This respresents the case when we're trying to determine if a URL belongs + // to the list where subresource filter should be active. + CHECK_URL_FOR_SUBRESOURCE_FILTER = 4, + // This represents the other cases when a check is being performed // synchronously so a client callback isn't required. For instance, when // trying to determing if an IP address is unsafe due to hosting Malware. - CHECK_OTHER = 4, + CHECK_OTHER = 5, }; // The information we need to process a URL safety reputation request and
diff --git a/components/safe_browsing_db/v4_local_database_manager_unittest.cc b/components/safe_browsing_db/v4_local_database_manager_unittest.cc index 2a1b2460..e005c18 100644 --- a/components/safe_browsing_db/v4_local_database_manager_unittest.cc +++ b/components/safe_browsing_db/v4_local_database_manager_unittest.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "components/safe_browsing_db/v4_local_database_manager.h" +#include "base/base64.h" #include "base/files/scoped_temp_dir.h" #include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" @@ -9,7 +11,6 @@ #include "base/test/test_simple_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "components/safe_browsing_db/v4_database.h" -#include "components/safe_browsing_db/v4_local_database_manager.h" #include "components/safe_browsing_db/v4_test_util.h" #include "content/public/test/test_browser_thread_bundle.h" #include "crypto/sha2.h" @@ -20,7 +21,7 @@ namespace { -typedef base::Callback<void()> NullCallback; +typedef std::vector<FullHashInfo> FullHashInfos; // Utility function for populating hashes. FullHash HashForUrl(const GURL& url) { @@ -36,39 +37,49 @@ FakeGetHashProtocolManager( net::URLRequestContextGetter* request_context_getter, const StoresToCheck& stores_to_check, - const V4ProtocolConfig& config) + const V4ProtocolConfig& config, + const FullHashInfos& full_hash_infos) : V4GetHashProtocolManager(request_context_getter, stores_to_check, - config) {} + config), + full_hash_infos_(full_hash_infos) {} void GetFullHashes(const FullHashToStoreAndHashPrefixesMap&, FullHashCallback callback) override { - std::vector<FullHashInfo> full_hash_infos; - // Async, since the real manager might use a fetcher. base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(callback, full_hash_infos)); + FROM_HERE, base::Bind(callback, full_hash_infos_)); } + + private: + FullHashInfos full_hash_infos_; }; class FakeGetHashProtocolManagerFactory : public V4GetHashProtocolManagerFactory { public: + FakeGetHashProtocolManagerFactory(const FullHashInfos& full_hash_infos) + : full_hash_infos_(full_hash_infos) {} + std::unique_ptr<V4GetHashProtocolManager> CreateProtocolManager( net::URLRequestContextGetter* request_context_getter, const StoresToCheck& stores_to_check, const V4ProtocolConfig& config) override { return base::MakeUnique<FakeGetHashProtocolManager>( - request_context_getter, stores_to_check, config); + request_context_getter, stores_to_check, config, full_hash_infos_); } + + private: + FullHashInfos full_hash_infos_; }; // Use FakeGetHashProtocolManagerFactory in scope, then reset. class ScopedFakeGetHashProtocolManagerFactory { public: - ScopedFakeGetHashProtocolManagerFactory() { + ScopedFakeGetHashProtocolManagerFactory( + const FullHashInfos& full_hash_infos) { V4GetHashProtocolManager::RegisterFactory( - base::MakeUnique<FakeGetHashProtocolManagerFactory>()); + base::MakeUnique<FakeGetHashProtocolManagerFactory>(full_hash_infos)); } ~ScopedFakeGetHashProtocolManagerFactory() { V4GetHashProtocolManager::RegisterFactory(nullptr); @@ -169,9 +180,7 @@ const std::string& threat_hash) override { DCHECK_EQ(expected_url, url); DCHECK_EQ(expected_sb_threat_type, threat_type); - // |threat_hash| is empty because GetFullHashes calls back with empty - // |full_hash_infos|. - DCHECK(threat_hash.empty()); + DCHECK_EQ(threat_type == SB_THREAT_TYPE_SAFE, threat_hash.empty()); on_check_resource_url_result_called_ = true; } @@ -447,7 +456,7 @@ // Verify that a window where checks cannot be cancelled is closed. TEST_F(V4LocalDatabaseManagerTest, CancelPending) { // Setup to receive full-hash misses. - ScopedFakeGetHashProtocolManagerFactory pin; + ScopedFakeGetHashProtocolManagerFactory pin(FullHashInfos({})); // Reset the database manager so it picks up the replacement protocol manager. ResetLocalDatabaseManager(); @@ -674,7 +683,7 @@ // This verifies the fix for race in http://crbug.com/660293 TEST_F(V4LocalDatabaseManagerTest, TestCheckBrowseUrlWithSameClientAndCancel) { - ScopedFakeGetHashProtocolManagerFactory pin; + ScopedFakeGetHashProtocolManagerFactory pin(FullHashInfos({})); // Reset the database manager so it picks up the replacement protocol manager. ResetLocalDatabaseManager(); WaitForTasksOnTaskRunner(); @@ -709,7 +718,7 @@ TEST_F(V4LocalDatabaseManagerTest, TestCheckResourceUrl) { // Setup to receive full-hash misses. - ScopedFakeGetHashProtocolManagerFactory pin; + ScopedFakeGetHashProtocolManagerFactory pin(FullHashInfos({})); // Reset the database manager so it picks up the replacement protocol manager. ResetLocalDatabaseManager(); @@ -732,6 +741,66 @@ EXPECT_TRUE(client.on_check_resource_url_result_called_); } +TEST_F(V4LocalDatabaseManagerTest, TestSubresourceFilterCallback) { + // Setup to receive full-hash misses. + ScopedFakeGetHashProtocolManagerFactory pin(FullHashInfos({})); + + // Reset the database manager so it picks up the replacement protocol manager. + ResetLocalDatabaseManager(); + WaitForTasksOnTaskRunner(); + + // An URL and matching prefix. + const GURL url("http://example.com/a/"); + const HashPrefix hash_prefix("eW\x1A\xF\xA9"); + + // Put a match in the db that will cause a protocol-manager request. + StoreAndHashPrefixes store_and_hash_prefixes; + store_and_hash_prefixes.emplace_back(GetUrlSubresourceFilterId(), + hash_prefix); + ReplaceV4Database(store_and_hash_prefixes, true /* stores_available */); + + // Test that a request flows through to the callback. + { + TestClient client(SB_THREAT_TYPE_SAFE, url); + EXPECT_FALSE( + v4_local_database_manager_->CheckUrlForSubresourceFilter(url, &client)); + EXPECT_FALSE(client.on_check_browse_url_result_called_); + WaitForTasksOnTaskRunner(); + EXPECT_TRUE(client.on_check_browse_url_result_called_); + } +} + +TEST_F(V4LocalDatabaseManagerTest, TestCheckResourceUrlReturnsBad) { + std::string base64_encoded = "ZVcaD6lke9GaaZEf07X3CpuEgMAqbpAyPw3sX/7eK9M="; + std::string base64_decoded; + base::Base64Decode(base64_encoded, &base64_decoded); + FullHashInfo fhi(base64_decoded, GetChromeUrlClientIncidentId(), + base::Time()); + + // Setup to receive full-hash hit. + ScopedFakeGetHashProtocolManagerFactory pin(FullHashInfos({fhi})); + + // Reset the database manager so it picks up the replacement protocol manager. + ResetLocalDatabaseManager(); + WaitForTasksOnTaskRunner(); + + // An URL and matching prefix. + const GURL url("http://example.com/a/"); + const HashPrefix hash_prefix("eW\x1A\xF\xA9"); + + // Put a match in the db that will cause a protocol-manager request. + StoreAndHashPrefixes store_and_hash_prefixes; + store_and_hash_prefixes.emplace_back(GetChromeUrlClientIncidentId(), + hash_prefix); + ReplaceV4Database(store_and_hash_prefixes, true /* stores_available */); + + TestClient client(SB_THREAT_TYPE_BLACKLISTED_RESOURCE, url); + EXPECT_FALSE(v4_local_database_manager_->CheckResourceUrl(url, &client)); + EXPECT_FALSE(client.on_check_resource_url_result_called_); + WaitForTasksOnTaskRunner(); + EXPECT_TRUE(client.on_check_resource_url_result_called_); +} + // TODO(nparker): Add tests for // CheckDownloadUrl() // CheckExtensionIDs()
diff --git a/components/safe_browsing_db/v4_protocol_manager_util.cc b/components/safe_browsing_db/v4_protocol_manager_util.cc index dad0d79..e210f97 100644 --- a/components/safe_browsing_db/v4_protocol_manager_util.cc +++ b/components/safe_browsing_db/v4_protocol_manager_util.cc
@@ -132,6 +132,10 @@ SOCIAL_ENGINEERING_PUBLIC); } +const ListIdentifier GetUrlSubresourceFilterId() { + return ListIdentifier(GetCurrentPlatformType(), URL, SUBRESOURCE_FILTER); +} + const ListIdentifier GetUrlUwsId() { return ListIdentifier(GetCurrentPlatformType(), URL, UNWANTED_SOFTWARE); }
diff --git a/components/safe_browsing_db/v4_protocol_manager_util.h b/components/safe_browsing_db/v4_protocol_manager_util.h index 707b82d..4ebb7830 100644 --- a/components/safe_browsing_db/v4_protocol_manager_util.h +++ b/components/safe_browsing_db/v4_protocol_manager_util.h
@@ -109,6 +109,9 @@ // Url abuses a permission API. SB_THREAT_TYPE_API_ABUSE, + + // Activation patterns for the Subresource Filter. + SB_THREAT_TYPE_SUBRESOURCE_FILTER, }; // The information required to uniquely identify each list the client is @@ -143,15 +146,16 @@ PlatformType GetCurrentPlatformType(); const ListIdentifier GetCertCsdDownloadWhitelistId(); const ListIdentifier GetChromeExtMalwareId(); -const ListIdentifier GetChromeUrlApiId(); const ListIdentifier GetChromeFilenameClientIncidentId(); +const ListIdentifier GetChromeUrlApiId(); const ListIdentifier GetChromeUrlClientIncidentId(); const ListIdentifier GetIpMalwareId(); const ListIdentifier GetUrlCsdDownloadWhitelistId(); const ListIdentifier GetUrlCsdWhitelistId(); -const ListIdentifier GetUrlMalwareId(); const ListIdentifier GetUrlMalBinId(); +const ListIdentifier GetUrlMalwareId(); const ListIdentifier GetUrlSocEngId(); +const ListIdentifier GetUrlSubresourceFilterId(); const ListIdentifier GetUrlUwsId(); // Represents the state of each store.
diff --git a/components/security_interstitials/core/controller_client.cc b/components/security_interstitials/core/controller_client.cc index e38fc18..22a3dce7 100644 --- a/components/security_interstitials/core/controller_client.cc +++ b/components/security_interstitials/core/controller_client.cc
@@ -19,7 +19,7 @@ const char kDisplayCheckBox[] = "displaycheckbox"; const char kOptInLink[] = "optInLink"; const char kPrivacyLinkHtml[] = - "<a id=\"privacy-link\" href=\"\" onclick=\"sendCommand(%d); " + "<a id=\"privacy-link\" href=\"#\" onclick=\"sendCommand(%d); " "return false;\" onmousedown=\"return false;\">%s</a>"; ControllerClient::ControllerClient(
diff --git a/components/sessions/content/content_serialized_navigation_driver.cc b/components/sessions/content/content_serialized_navigation_driver.cc index 7aa7de8..d9e4b1c7 100644 --- a/components/sessions/content/content_serialized_navigation_driver.cc +++ b/components/sessions/content/content_serialized_navigation_driver.cc
@@ -7,6 +7,7 @@ #include "base/memory/singleton.h" #include "build/build_config.h" #include "components/sessions/core/serialized_navigation_entry.h" +#include "content/public/common/content_features.h" #include "content/public/common/page_state.h" #include "content/public/common/referrer.h" #include "content/public/common/url_constants.h" @@ -138,6 +139,27 @@ navigation->encoded_page_state_ = content::PageState::CreateFromURL( navigation->virtual_url_).ToEncodedData(); } + + if (base::FeatureList::IsEnabled(features::kNativeAndroidHistoryManager) && + navigation->virtual_url_.SchemeIs(content::kChromeUIScheme) && + (navigation->virtual_url_.host_piece() == content::kChromeUIHistoryHost || + navigation->virtual_url_.host_piece() == + content::kChromeUIHistoryFrameHost)) { + // Rewrite the old history Web UI to the new android native history. + navigation->virtual_url_ = GURL(content::kChromeUINativeHistoryURL); + navigation->original_request_url_ = navigation->virtual_url_; + navigation->encoded_page_state_ = content::PageState::CreateFromURL( + navigation->virtual_url_).ToEncodedData(); + } else if ( + !base::FeatureList::IsEnabled(features::kNativeAndroidHistoryManager) && + navigation->virtual_url_.SchemeIs(content::kChromeNativeUIScheme) && + navigation->virtual_url_.host_piece() == content::kChromeUIHistoryHost) { + // If the android native history UI has been disabled, redirect + // chrome-native://history to the old web UI. + navigation->virtual_url_ = GURL(content::kChromeUIHistoryURL); + navigation->original_request_url_ = navigation->virtual_url_; + navigation->encoded_page_state_ = std::string(); + } #endif // defined(OS_ANDROID) }
diff --git a/components/signin/core/browser/webdata/token_service_table.cc b/components/signin/core/browser/webdata/token_service_table.cc index d1ccb08..b367f8f 100644 --- a/components/signin/core/browser/webdata/token_service_table.cc +++ b/components/signin/core/browser/webdata/token_service_table.cc
@@ -8,6 +8,7 @@ #include <string> #include "base/logging.h" +#include "base/metrics/histogram_macros.h" #include "components/os_crypt/os_crypt.h" #include "components/webdata/common/web_database.h" #include "sql/statement.h" @@ -21,6 +22,14 @@ return reinterpret_cast<void*>(&table_key); } +// Entries in the |Signin.TokenTable.ReadTokenFromDBResult| histogram. +enum ReadOneTokenResult { + READ_ONE_TOKEN_SUCCESS, + READ_ONE_TOKEN_DB_SUCCESS_DECRYPT_FAILED, + READ_ONE_TOKEN_DB_FAILED_BAD_ENTRY, + READ_ONE_TOKEN_MAX_VALUE +}; + } // namespace TokenServiceTable* TokenServiceTable::FromWebDatabase(WebDatabase* db) { @@ -93,10 +102,18 @@ sql::Statement s(db_->GetUniqueStatement( "SELECT service, encrypted_token FROM token_service")); - if (!s.is_valid()) - return false; + UMA_HISTOGRAM_BOOLEAN("Signin.TokenTable.GetAllTokensSqlStatementValidity", + s.is_valid()); + if (!s.is_valid()) { + LOG(ERROR) << "Failed to load tokens (invalid SQL statement)."; + return false; + } + + bool read_all_tokens_result = true; while (s.Step()) { + ReadOneTokenResult read_token_result = READ_ONE_TOKEN_MAX_VALUE; + std::string encrypted_token; std::string decrypted_token; std::string service; @@ -104,12 +121,25 @@ bool entry_ok = !service.empty() && s.ColumnBlobAsString(1, &encrypted_token); if (entry_ok) { - OSCrypt::DecryptString(encrypted_token, &decrypted_token); - (*tokens)[service] = decrypted_token; + if (OSCrypt::DecryptString(encrypted_token, &decrypted_token)) { + (*tokens)[service] = decrypted_token; + read_token_result = READ_ONE_TOKEN_SUCCESS; + } else { + // Chrome relies on native APIs to encrypt and decrypt the tokens which + // may fail (see http://crbug.com/686485). + LOG(ERROR) << "Failed to decrypt token for service " << service; + read_token_result = READ_ONE_TOKEN_DB_SUCCESS_DECRYPT_FAILED; + read_all_tokens_result = false; + } } else { - NOTREACHED(); - return false; + LOG(ERROR) << "Bad token entry for service " << service; + read_token_result = READ_ONE_TOKEN_DB_FAILED_BAD_ENTRY; + read_all_tokens_result = false; } + DCHECK_LT(read_token_result, READ_ONE_TOKEN_MAX_VALUE); + UMA_HISTOGRAM_ENUMERATION("Signin.TokenTable.ReadTokenFromDBResult", + read_token_result, + READ_ONE_TOKEN_MAX_VALUE); } - return true; + return read_all_tokens_result; }
diff --git a/components/subresource_filter/content/DEPS b/components/subresource_filter/content/DEPS index 920f470..9143c9f 100644 --- a/components/subresource_filter/content/DEPS +++ b/components/subresource_filter/content/DEPS
@@ -1,6 +1,5 @@ include_rules = [ "+components/subresource_filter/content/common", - "+content/public/browser", "+content/public/common", "+ipc", ]
diff --git a/components/subresource_filter/content/browser/DEPS b/components/subresource_filter/content/browser/DEPS index 2e01c67..f5b44b7b 100644 --- a/components/subresource_filter/content/browser/DEPS +++ b/components/subresource_filter/content/browser/DEPS
@@ -1,8 +1,5 @@ include_rules = [ "+components/keyed_service/core", "+content/public/browser", - "+content/public/common", - "+content/public/test", - "+ipc", "+components/safe_browsing_db", ]
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc index 63942318..c9125d2 100644 --- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc +++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
@@ -147,8 +147,13 @@ const GURL& url) const { switch (GetCurrentActivationScope()) { case ActivationScope::ALL_SITES: - return !IsWhitelisted(url); + return url.SchemeIsHTTPOrHTTPS() && !IsWhitelisted(url); case ActivationScope::ACTIVATION_LIST: + // The logic to ensure only http/https URLs are activated lives in + // AddActivationListMatch to ensure the activation list only has relevant + // entries. + DCHECK(url.SchemeIsHTTPOrHTTPS() || + !DidURLMatchCurrentActivationList(url)); return DidURLMatchCurrentActivationList(url) && !IsWhitelisted(url); default: return false; @@ -315,7 +320,7 @@ void ContentSubresourceFilterDriverFactory::AddActivationListMatch( const GURL& url, ActivationList match_type) { - if (!url.host().empty() && url.SchemeIsHTTPOrHTTPS()) + if (url.has_host() && url.SchemeIsHTTPOrHTTPS()) activation_list_matches_[DistillURLToHostAndPath(url)].insert(match_type); }
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc index 07e4429367..fa76b0dc 100644 --- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc +++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
@@ -602,6 +602,39 @@ } }; +// Only main frames with http/https schemes should activate, unless the +// activation scope is for all sites. +TEST_P(ContentSubresourceFilterDriverFactoryActivationScopeTest, + ActivateForSupportedUrlScheme) { + const ActivationScopeTestData& test_data = GetParam(); + base::FieldTrialList field_trial_list(nullptr); + testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle( + base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled, + test_data.activation_scope, + kActivationListSocialEngineeringAdsInterstitial); + + const char* unsupported_urls[] = { + "data:text/html,<p>Hello", "ftp://example.com/", "chrome://settings", + "chrome-extension://some-extension", "file:///var/www/index.html"}; + const char* supported_urls[] = {"http://example.test", + "https://example.test"}; + for (const auto url : unsupported_urls) { + SCOPED_TRACE(url); + RedirectChainMatchPattern expected_pattern = EMPTY; + NavigateAndExpectActivation({test_data.url_matches_activation_list}, + {GURL(url)}, expected_pattern, + false /* expected_activation */); + } + for (const auto url : supported_urls) { + SCOPED_TRACE(url); + RedirectChainMatchPattern expected_pattern = + test_data.url_matches_activation_list ? NO_REDIRECTS_HIT : EMPTY; + NavigateAndExpectActivation({test_data.url_matches_activation_list}, + {GURL(url)}, expected_pattern, + test_data.expected_activation); + } +}; + INSTANTIATE_TEST_CASE_P(NoSocEngHit, ContentSubresourceFilterDriverFactoryThreatTypeTest, ::testing::ValuesIn(kActivationListTestData));
diff --git a/components/subresource_filter/content/common/BUILD.gn b/components/subresource_filter/content/common/BUILD.gn index 0ccab98c..d309bf79 100644 --- a/components/subresource_filter/content/common/BUILD.gn +++ b/components/subresource_filter/content/common/BUILD.gn
@@ -5,6 +5,8 @@ static_library("common") { sources = [ "document_load_statistics.h", + "document_subresource_filter.cc", + "document_subresource_filter.h", "ruleset_dealer.cc", "ruleset_dealer.h", "subresource_filter_message_generator.cc", @@ -21,15 +23,18 @@ source_set("unit_tests") { testonly = true sources = [ + "document_subresource_filter_unittest.cc", "ruleset_dealer_unittest.cc", ] deps = [ ":common", "//base", + "//base/test:test_support", "//components/subresource_filter/core/common", "//components/subresource_filter/core/common:test_support", "//testing/gmock", "//testing/gtest", + "//third_party/WebKit/public:blink", "//url", ] }
diff --git a/components/subresource_filter/content/common/DEPS b/components/subresource_filter/content/common/DEPS new file mode 100644 index 0000000..cda6df7 --- /dev/null +++ b/components/subresource_filter/content/common/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+third_party/WebKit/public/platform", +]
diff --git a/components/subresource_filter/content/common/document_subresource_filter.cc b/components/subresource_filter/content/common/document_subresource_filter.cc new file mode 100644 index 0000000..b53a956a --- /dev/null +++ b/components/subresource_filter/content/common/document_subresource_filter.cc
@@ -0,0 +1,211 @@ +// 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. + +#include "components/subresource_filter/content/common/document_subresource_filter.h" + +#include <climits> + +#include "base/logging.h" +#include "base/strings/string_piece.h" +#include "base/strings/string_util.h" +#include "base/trace_event/trace_event.h" +#include "components/subresource_filter/core/common/first_party_origin.h" +#include "components/subresource_filter/core/common/memory_mapped_ruleset.h" +#include "components/subresource_filter/core/common/scoped_timers.h" +#include "components/subresource_filter/core/common/time_measurements.h" +#include "third_party/WebKit/public/platform/WebURL.h" + +namespace subresource_filter { + +namespace { + +proto::ElementType ToElementType( + blink::WebURLRequest::RequestContext request_context) { + switch (request_context) { + case blink::WebURLRequest::RequestContextAudio: + case blink::WebURLRequest::RequestContextVideo: + case blink::WebURLRequest::RequestContextTrack: + return proto::ELEMENT_TYPE_MEDIA; + case blink::WebURLRequest::RequestContextBeacon: + case blink::WebURLRequest::RequestContextPing: + return proto::ELEMENT_TYPE_PING; + case blink::WebURLRequest::RequestContextEmbed: + case blink::WebURLRequest::RequestContextObject: + case blink::WebURLRequest::RequestContextPlugin: + return proto::ELEMENT_TYPE_OBJECT; + case blink::WebURLRequest::RequestContextEventSource: + case blink::WebURLRequest::RequestContextFetch: + case blink::WebURLRequest::RequestContextXMLHttpRequest: + return proto::ELEMENT_TYPE_XMLHTTPREQUEST; + case blink::WebURLRequest::RequestContextFavicon: + case blink::WebURLRequest::RequestContextImage: + case blink::WebURLRequest::RequestContextImageSet: + return proto::ELEMENT_TYPE_IMAGE; + case blink::WebURLRequest::RequestContextFont: + return proto::ELEMENT_TYPE_FONT; + case blink::WebURLRequest::RequestContextFrame: + case blink::WebURLRequest::RequestContextForm: + case blink::WebURLRequest::RequestContextHyperlink: + case blink::WebURLRequest::RequestContextIframe: + case blink::WebURLRequest::RequestContextInternal: + case blink::WebURLRequest::RequestContextLocation: + return proto::ELEMENT_TYPE_SUBDOCUMENT; + case blink::WebURLRequest::RequestContextScript: + case blink::WebURLRequest::RequestContextServiceWorker: + case blink::WebURLRequest::RequestContextSharedWorker: + return proto::ELEMENT_TYPE_SCRIPT; + case blink::WebURLRequest::RequestContextStyle: + case blink::WebURLRequest::RequestContextXSLT: + return proto::ELEMENT_TYPE_STYLESHEET; + + case blink::WebURLRequest::RequestContextPrefetch: + case blink::WebURLRequest::RequestContextSubresource: + return proto::ELEMENT_TYPE_OTHER; + + case blink::WebURLRequest::RequestContextCSPReport: + case blink::WebURLRequest::RequestContextDownload: + case blink::WebURLRequest::RequestContextImport: + case blink::WebURLRequest::RequestContextManifest: + case blink::WebURLRequest::RequestContextUnspecified: + default: + return proto::ELEMENT_TYPE_UNSPECIFIED; + } +} + +ActivationState ComputeActivationStateImpl( + const GURL& document_url, + const url::Origin& parent_document_origin, + const ActivationState& parent_activation_state, + const IndexedRulesetMatcher& matcher) { + ActivationState activation_state = parent_activation_state; + if (activation_state.filtering_disabled_for_document) + return activation_state; + + // TODO(pkalinnikov): Match several activation types in a batch. + if (matcher.ShouldDisableFilteringForDocument( + document_url, parent_document_origin, + proto::ACTIVATION_TYPE_DOCUMENT)) { + activation_state.filtering_disabled_for_document = true; + } else if (!activation_state.generic_blocking_rules_disabled && + matcher.ShouldDisableFilteringForDocument( + document_url, parent_document_origin, + proto::ACTIVATION_TYPE_GENERICBLOCK)) { + activation_state.generic_blocking_rules_disabled = true; + } + return activation_state; +} + +} // namespace + +ActivationState ComputeActivationState( + const GURL& document_url, + const url::Origin& parent_document_origin, + const ActivationState& parent_activation_state, + const MemoryMappedRuleset* ruleset) { + DCHECK(ruleset); + IndexedRulesetMatcher matcher(ruleset->data(), ruleset->length()); + return ComputeActivationStateImpl(document_url, parent_document_origin, + parent_activation_state, matcher); +} + +ActivationState ComputeActivationState( + ActivationLevel activation_level, + bool measure_performance, + const std::vector<GURL>& ancestor_document_urls, + const MemoryMappedRuleset* ruleset) { + SCOPED_UMA_HISTOGRAM_MICRO_TIMER( + "SubresourceFilter.DocumentLoad.Activation.WallDuration"); + SCOPED_UMA_HISTOGRAM_MICRO_THREAD_TIMER( + "SubresourceFilter.DocumentLoad.Activation.CPUDuration"); + + ActivationState activation_state(activation_level); + activation_state.measure_performance = measure_performance; + DCHECK(ruleset); + + IndexedRulesetMatcher matcher(ruleset->data(), ruleset->length()); + + url::Origin parent_document_origin; + for (auto iter = ancestor_document_urls.rbegin(), + rend = ancestor_document_urls.rend(); + iter != rend; ++iter) { + const GURL& document_url(*iter); + activation_state = ComputeActivationStateImpl( + document_url, parent_document_origin, activation_state, matcher); + parent_document_origin = url::Origin(document_url); + } + + return activation_state; +} + +DocumentSubresourceFilter::DocumentSubresourceFilter( + url::Origin document_origin, + ActivationState activation_state, + scoped_refptr<const MemoryMappedRuleset> ruleset, + base::OnceClosure first_disallowed_load_callback) + : activation_state_(activation_state), + ruleset_(std::move(ruleset)), + ruleset_matcher_(ruleset_->data(), ruleset_->length()), + first_disallowed_load_callback_( + std::move(first_disallowed_load_callback)) { + DCHECK_NE(activation_state_.activation_level, ActivationLevel::DISABLED); + if (!activation_state_.filtering_disabled_for_document) + document_origin_.reset(new FirstPartyOrigin(std::move(document_origin))); +} + +DocumentSubresourceFilter::~DocumentSubresourceFilter() = default; + +blink::WebDocumentSubresourceFilter::LoadPolicy +DocumentSubresourceFilter::getLoadPolicy( + const blink::WebURL& resourceUrl, + blink::WebURLRequest::RequestContext request_context) { + TRACE_EVENT1("loader", "DocumentSubresourceFilter::getLoadPolicy", "url", + resourceUrl.string().utf8()); + + auto wall_duration_timer = ScopedTimers::StartIf( + activation_state_.measure_performance && + ScopedThreadTimers::IsSupported(), + [this](base::TimeDelta delta) { + statistics_.evaluation_total_wall_duration += delta; + UMA_HISTOGRAM_MICRO_TIMES( + "SubresourceFilter.SubresourceLoad.Evaluation.WallDuration", delta); + }); + auto cpu_duration_timer = ScopedThreadTimers::StartIf( + activation_state_.measure_performance, [this](base::TimeDelta delta) { + statistics_.evaluation_total_cpu_duration += delta; + UMA_HISTOGRAM_MICRO_TIMES( + "SubresourceFilter.SubresourceLoad.Evaluation.CPUDuration", delta); + }); + + ++statistics_.num_loads_total; + + if (activation_state_.filtering_disabled_for_document) + return Allow; + + if (resourceUrl.protocolIs(url::kDataScheme)) + return Allow; + + ++statistics_.num_loads_evaluated; + DCHECK(document_origin_); + if (ruleset_matcher_.ShouldDisallowResourceLoad( + GURL(resourceUrl), *document_origin_, ToElementType(request_context), + activation_state_.generic_blocking_rules_disabled)) { + ++statistics_.num_loads_matching_rules; + if (activation_state_.activation_level == ActivationLevel::ENABLED) { + ++statistics_.num_loads_disallowed; + return Disallow; + } else if (activation_state_.activation_level == ActivationLevel::DRYRUN) { + return WouldDisallow; + } + } + return Allow; +} + +void DocumentSubresourceFilter::reportDisallowedLoad() { + if (first_disallowed_load_callback_.is_null()) + return; + + std::move(first_disallowed_load_callback_).Run(); +} + +} // namespace subresource_filter
diff --git a/components/subresource_filter/content/common/document_subresource_filter.h b/components/subresource_filter/content/common/document_subresource_filter.h new file mode 100644 index 0000000..bfe438b --- /dev/null +++ b/components/subresource_filter/content/common/document_subresource_filter.h
@@ -0,0 +1,96 @@ +// 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 COMPONENTS_SUBRESOURCE_FILTER_CONTENT_COMMON_DOCUMENT_SUBRESOURCE_FILTER_H_ +#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_COMMON_DOCUMENT_SUBRESOURCE_FILTER_H_ + +#include <stddef.h> + +#include <memory> +#include <vector> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "base/time/time.h" +#include "components/subresource_filter/content/common/document_load_statistics.h" +#include "components/subresource_filter/core/common/activation_level.h" +#include "components/subresource_filter/core/common/activation_state.h" +#include "components/subresource_filter/core/common/indexed_ruleset.h" +#include "third_party/WebKit/public/platform/WebDocumentSubresourceFilter.h" +#include "url/gurl.h" +#include "url/origin.h" + +namespace subresource_filter { + +class FirstPartyOrigin; +class MemoryMappedRuleset; + +// Computes whether/how subresource filtering should be activated while loading +// |document_url| in a frame, based on the parent document's |activation_state|, +// the |parent_document_origin|, as well as any applicable deactivation rules in +// non-null |ruleset|. +ActivationState ComputeActivationState( + const GURL& document_url, + const url::Origin& parent_document_origin, + const ActivationState& parent_activation_state, + const MemoryMappedRuleset* ruleset); + +// Same as above, but instead of relying on the pre-computed activation state of +// the parent, computes the activation state for a frame from scratch, based on +// the page-level activation options |activation_level| and +// |measure_performance|; as well as any deactivation rules in |ruleset| that +// apply to |ancestor_document_urls|. +// +// TODO(pkalinnikov): Remove this when browser-side navigation is supported. +ActivationState ComputeActivationState( + ActivationLevel activation_level, + bool measure_performance, + const std::vector<GURL>& ancestor_document_urls, + const MemoryMappedRuleset* ruleset); + +// Performs filtering of subresource loads in the scope of a given document. +class DocumentSubresourceFilter + : public blink::WebDocumentSubresourceFilter, + public base::SupportsWeakPtr<DocumentSubresourceFilter> { + public: + // Constructs a new filter that will: + // -- Operate in a manner prescribed in |activation_state|. + // -- Filter subresource loads in the scope of a document loaded from + // |document_origin|. + // -- Hold a reference to and use |ruleset| for its entire lifetime. + // -- Invoke |first_disallowed_load_callback|, if it is non-null, on the + // first disallowed subresource load. + DocumentSubresourceFilter(url::Origin document_origin, + ActivationState activation_state, + scoped_refptr<const MemoryMappedRuleset> ruleset, + base::OnceClosure first_disallowed_load_callback); + + ~DocumentSubresourceFilter() override; + + const DocumentLoadStatistics& statistics() const { return statistics_; } + + // blink::WebDocumentSubresourceFilter: + LoadPolicy getLoadPolicy(const blink::WebURL& resourceUrl, + blink::WebURLRequest::RequestContext) override; + void reportDisallowedLoad() override; + + private: + const ActivationState activation_state_; + const scoped_refptr<const MemoryMappedRuleset> ruleset_; + const IndexedRulesetMatcher ruleset_matcher_; + + // Equals nullptr iff |activation_state_.filtering_disabled_for_document|. + std::unique_ptr<FirstPartyOrigin> document_origin_; + + base::OnceClosure first_disallowed_load_callback_; + DocumentLoadStatistics statistics_; + + DISALLOW_COPY_AND_ASSIGN(DocumentSubresourceFilter); +}; + +} // namespace subresource_filter + +#endif // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_COMMON_DOCUMENT_SUBRESOURCE_FILTER_H_
diff --git a/components/subresource_filter/content/common/document_subresource_filter_unittest.cc b/components/subresource_filter/content/common/document_subresource_filter_unittest.cc new file mode 100644 index 0000000..b7550af --- /dev/null +++ b/components/subresource_filter/content/common/document_subresource_filter_unittest.cc
@@ -0,0 +1,329 @@ +// 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. + +#include "components/subresource_filter/content/common/document_subresource_filter.h" + +#include "base/bind.h" +#include "base/callback.h" +#include "base/files/file.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/strings/string_piece.h" +#include "components/subresource_filter/core/common/memory_mapped_ruleset.h" +#include "components/subresource_filter/core/common/test_ruleset_creator.h" +#include "components/subresource_filter/core/common/test_ruleset_utils.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/public/platform/WebURL.h" +#include "third_party/WebKit/public/platform/WebURLRequest.h" +#include "url/gurl.h" + +namespace subresource_filter { + +namespace { + +constexpr auto kDisabled = ActivationLevel::DISABLED; +constexpr auto kDryRun = ActivationLevel::DRYRUN; +constexpr auto kEnabled = ActivationLevel::ENABLED; + +const char kTestAlphaURL[] = "http://example.com/alpha"; +const char kTestAlphaDataURI[] = "data:text/plain,alpha"; +const char kTestBetaURL[] = "http://example.com/beta"; + +const char kTestAlphaURLPathSuffix[] = "alpha"; + +class TestCallbackReceiver { + public: + TestCallbackReceiver() = default; + base::OnceClosure closure() { + return base::BindOnce(&TestCallbackReceiver::CallbackMethod, + base::Unretained(this)); + } + size_t callback_count() const { return callback_count_; } + + private: + void CallbackMethod() { ++callback_count_; } + + size_t callback_count_ = 0; + + DISALLOW_COPY_AND_ASSIGN(TestCallbackReceiver); +}; + +} // namespace + +// Tests for DocumentSubresourceFilter class. ---------------------------------- + +class DocumentSubresourceFilterTest : public ::testing::Test { + public: + DocumentSubresourceFilterTest() {} + + protected: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE( + SetTestRulesetToDisallowURLsWithPathSuffix(kTestAlphaURLPathSuffix)); + } + + void SetTestRulesetToDisallowURLsWithPathSuffix(base::StringPiece suffix) { + testing::TestRulesetPair test_ruleset_pair; + ASSERT_NO_FATAL_FAILURE( + test_ruleset_creator_.CreateRulesetToDisallowURLsWithPathSuffix( + suffix, &test_ruleset_pair)); + ruleset_ = new MemoryMappedRuleset( + testing::TestRuleset::Open(test_ruleset_pair.indexed)); + } + + const MemoryMappedRuleset* ruleset() { return ruleset_.get(); } + + private: + testing::TestRulesetCreator test_ruleset_creator_; + scoped_refptr<const MemoryMappedRuleset> ruleset_; + + DISALLOW_COPY_AND_ASSIGN(DocumentSubresourceFilterTest); +}; + +TEST_F(DocumentSubresourceFilterTest, DryRun) { + blink::WebURLRequest::RequestContext request_context = + blink::WebURLRequest::RequestContextImage; + TestCallbackReceiver first_disallowed_load_callback_receiver; + + ActivationState activation_state(kDryRun); + activation_state.measure_performance = true; + DocumentSubresourceFilter filter( + url::Origin(), activation_state, ruleset(), + first_disallowed_load_callback_receiver.closure()); + + EXPECT_EQ(blink::WebDocumentSubresourceFilter::WouldDisallow, + filter.getLoadPolicy(GURL(kTestAlphaURL), request_context)); + EXPECT_EQ(blink::WebDocumentSubresourceFilter::Allow, + filter.getLoadPolicy(GURL(kTestAlphaDataURI), request_context)); + EXPECT_EQ(blink::WebDocumentSubresourceFilter::Allow, + filter.getLoadPolicy(GURL(kTestBetaURL), request_context)); + + const auto& statistics = filter.statistics(); + EXPECT_EQ(3, statistics.num_loads_total); + EXPECT_EQ(2, statistics.num_loads_evaluated); + EXPECT_EQ(1, statistics.num_loads_matching_rules); + EXPECT_EQ(0, statistics.num_loads_disallowed); + + EXPECT_EQ(0u, first_disallowed_load_callback_receiver.callback_count()); +} + +TEST_F(DocumentSubresourceFilterTest, Enabled) { + auto test_impl = [this](bool measure_performance) { + blink::WebURLRequest::RequestContext request_context = + blink::WebURLRequest::RequestContextImage; + ActivationState activation_state(kEnabled); + activation_state.measure_performance = measure_performance; + DocumentSubresourceFilter filter(url::Origin(), activation_state, ruleset(), + base::OnceClosure()); + EXPECT_EQ(blink::WebDocumentSubresourceFilter::Disallow, + filter.getLoadPolicy(GURL(kTestAlphaURL), request_context)); + EXPECT_EQ(blink::WebDocumentSubresourceFilter::Allow, + filter.getLoadPolicy(GURL(kTestAlphaDataURI), request_context)); + EXPECT_EQ(blink::WebDocumentSubresourceFilter::Allow, + filter.getLoadPolicy(GURL(kTestBetaURL), request_context)); + + const auto& statistics = filter.statistics(); + EXPECT_EQ(3, statistics.num_loads_total); + EXPECT_EQ(2, statistics.num_loads_evaluated); + EXPECT_EQ(1, statistics.num_loads_matching_rules); + EXPECT_EQ(1, statistics.num_loads_disallowed); + + if (!measure_performance) { + EXPECT_TRUE(statistics.evaluation_total_cpu_duration.is_zero()); + EXPECT_TRUE(statistics.evaluation_total_wall_duration.is_zero()); + } + // Otherwise, don't expect |total_duration| to be non-zero, although it + // practically is (when timer is supported). + }; + + test_impl(true /* measure_performance */); + test_impl(false /* measure_performance */); +} + +TEST_F(DocumentSubresourceFilterTest, + CallbackFiredExactlyOnceAfterFirstDisallowedLoad) { + TestCallbackReceiver first_disallowed_load_callback_receiver; + + ActivationState activation_state(kEnabled); + activation_state.measure_performance = true; + DocumentSubresourceFilter filter( + url::Origin(), activation_state, ruleset(), + first_disallowed_load_callback_receiver.closure()); + + EXPECT_EQ(0u, first_disallowed_load_callback_receiver.callback_count()); + filter.reportDisallowedLoad(); + EXPECT_EQ(1u, first_disallowed_load_callback_receiver.callback_count()); + filter.reportDisallowedLoad(); + EXPECT_EQ(1u, first_disallowed_load_callback_receiver.callback_count()); +} + +// Tests for ComputeActivationState functions. --------------------------------- + +class SubresourceFilterComputeActivationStateTest : public ::testing::Test { + public: + SubresourceFilterComputeActivationStateTest() {} + + protected: + void SetUp() override { + constexpr int32_t kDocument = proto::ACTIVATION_TYPE_DOCUMENT; + constexpr int32_t kGenericBlock = proto::ACTIVATION_TYPE_GENERICBLOCK; + + std::vector<proto::UrlRule> rules; + rules.push_back(testing::CreateWhitelistRuleForDocument( + "child1.com", kDocument, {"parent1.com", "parent2.com"})); + rules.push_back(testing::CreateWhitelistRuleForDocument( + "child2.com", kGenericBlock, {"parent1.com", "parent2.com"})); + rules.push_back(testing::CreateWhitelistRuleForDocument( + "child3.com", kDocument | kGenericBlock, + {"parent1.com", "parent2.com"})); + + testing::TestRulesetPair test_ruleset_pair; + ASSERT_NO_FATAL_FAILURE(test_ruleset_creator_.CreateRulesetWithRules( + rules, &test_ruleset_pair)); + ruleset_ = new MemoryMappedRuleset( + testing::TestRuleset::Open(test_ruleset_pair.indexed)); + } + + static ActivationState MakeState( + bool filtering_disabled_for_document, + bool generic_blocking_rules_disabled = false, + ActivationLevel activation_level = kEnabled) { + ActivationState activation_state(activation_level); + activation_state.filtering_disabled_for_document = + filtering_disabled_for_document; + activation_state.generic_blocking_rules_disabled = + generic_blocking_rules_disabled; + return activation_state; + }; + + const MemoryMappedRuleset* ruleset() { return ruleset_.get(); } + + private: + testing::TestRulesetCreator test_ruleset_creator_; + scoped_refptr<const MemoryMappedRuleset> ruleset_; + + DISALLOW_COPY_AND_ASSIGN(SubresourceFilterComputeActivationStateTest); +}; + +TEST_F(SubresourceFilterComputeActivationStateTest, + ActivationBitsCorrectlyPropagateToChildDocument) { + // Make sure that the |generic_blocking_rules_disabled| flag is disregarded + // when |filtering_disabled_for_document| is true. + ASSERT_EQ(MakeState(true, false), MakeState(true, true)); + + // TODO(pkalinnikov): Find a short way to express all these tests. + const struct { + const char* document_url; + const char* parent_document_origin; + ActivationState parent_activation; + ActivationState expected_activation_state; + } kTestCases[] = { + {"http://example.com", "http://example.com", MakeState(false, false), + MakeState(false, false)}, + {"http://example.com", "http://example.com", MakeState(false, true), + MakeState(false, true)}, + {"http://example.com", "http://example.com", MakeState(true, false), + MakeState(true)}, + {"http://example.com", "http://example.com", MakeState(true, true), + MakeState(true)}, + + {"http://child1.com", "http://parrrrent1.com", MakeState(false, false), + MakeState(false, false)}, + {"http://child1.com", "http://parent1.com", MakeState(false, false), + MakeState(true, false)}, + {"http://child1.com", "http://parent2.com", MakeState(false, false), + MakeState(true, false)}, + {"http://child1.com", "http://parent2.com", MakeState(true, false), + MakeState(true)}, + {"http://child1.com", "http://parent2.com", MakeState(false, true), + MakeState(true)}, + + {"http://child2.com", "http://parent1.com", MakeState(false, false), + MakeState(false, true)}, + {"http://child2.com", "http://parent1.com", MakeState(false, true), + MakeState(false, true)}, + {"http://child2.com", "http://parent1.com", MakeState(true, false), + MakeState(true)}, + {"http://child2.com", "http://parent1.com", MakeState(true, true), + MakeState(true)}, + + {"http://child3.com", "http://parent1.com", MakeState(false, false), + MakeState(true)}, + {"http://child3.com", "http://parent1.com", MakeState(false, true), + MakeState(true)}, + {"http://child3.com", "http://parent1.com", MakeState(true, false), + MakeState(true)}, + {"http://child3.com", "http://parent1.com", MakeState(true, true), + MakeState(true)}, + }; + + for (size_t i = 0, size = arraysize(kTestCases); i != size; ++i) { + SCOPED_TRACE(::testing::Message() << "Test number: " << i); + const auto& test_case = kTestCases[i]; + + GURL document_url(test_case.document_url); + url::Origin parent_document_origin(GURL(test_case.parent_document_origin)); + ActivationState activation_state = + ComputeActivationState(document_url, parent_document_origin, + test_case.parent_activation, ruleset()); + EXPECT_EQ(test_case.expected_activation_state, activation_state); + } +} + +TEST_F(SubresourceFilterComputeActivationStateTest, + ActivationStateCorrectlyPropagatesDownDocumentHierarchy) { + const struct { + std::vector<std::string> ancestor_document_urls; + ActivationLevel activation_level; + ActivationState expected_activation_state; + } kTestCases[] = { + {{"http://example.com"}, kEnabled, MakeState(false)}, + {std::vector<std::string>(2, "http://example.com"), kEnabled, + MakeState(false)}, + {std::vector<std::string>(4, "http://example.com"), kEnabled, + MakeState(false)}, + + {std::vector<std::string>(4, "http://example.com"), kEnabled, + MakeState(false, false, kEnabled)}, + {std::vector<std::string>(4, "http://example.com"), kDisabled, + MakeState(false, false, kDisabled)}, + {std::vector<std::string>(4, "http://example.com"), kDryRun, + MakeState(false, false, kDryRun)}, + + {{"http://ex.com", "http://child1.com", "http://parent1.com", + "http://root.com"}, + kEnabled, + MakeState(true)}, + + {{"http://ex.com", "http://child1.com", "http://parent1.com", + "http://root.com"}, + kEnabled, + MakeState(true)}, + + {{"http://ex.com", "http://child2.com", "http://parent1.com", + "http://root.com"}, + kEnabled, + MakeState(false, true)}, + + {{"http://ex.com", "http://ex.com", "http://child3.com", + "http://parent1.com", "http://root.com"}, + kDryRun, + MakeState(true, false, kDryRun)}, + }; + + for (size_t i = 0, size = arraysize(kTestCases); i != size; ++i) { + const auto& test_case = kTestCases[i]; + SCOPED_TRACE(::testing::Message() << "Test number: " << i); + + std::vector<GURL> ancestor_document_urls; + for (const auto& url_string : test_case.ancestor_document_urls) + ancestor_document_urls.emplace_back(url_string); + + ActivationState activation_state = ComputeActivationState( + test_case.activation_level, false, ancestor_document_urls, ruleset()); + EXPECT_EQ(test_case.expected_activation_state, activation_state); + } +} + +} // namespace subresource_filter
diff --git a/components/subresource_filter/content/renderer/BUILD.gn b/components/subresource_filter/content/renderer/BUILD.gn index 5ff1f78..72890402 100644 --- a/components/subresource_filter/content/renderer/BUILD.gn +++ b/components/subresource_filter/content/renderer/BUILD.gn
@@ -4,8 +4,6 @@ static_library("renderer") { sources = [ - "document_subresource_filter.cc", - "document_subresource_filter.h", "subresource_filter_agent.cc", "subresource_filter_agent.h", "unverified_ruleset_dealer.cc", @@ -25,7 +23,6 @@ source_set("unit_tests") { testonly = true sources = [ - "document_subresource_filter_unittest.cc", "subresource_filter_agent_unittest.cc", ] deps = [ @@ -35,7 +32,6 @@ "//components/subresource_filter/content/common", "//components/subresource_filter/core/common", "//components/subresource_filter/core/common:test_support", - "//content/public/renderer", "//testing/gmock", "//testing/gtest", "//third_party/WebKit/public:blink",
diff --git a/components/subresource_filter/content/renderer/document_subresource_filter.cc b/components/subresource_filter/content/renderer/document_subresource_filter.cc deleted file mode 100644 index 42da608..0000000 --- a/components/subresource_filter/content/renderer/document_subresource_filter.cc +++ /dev/null
@@ -1,177 +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. - -#include "components/subresource_filter/content/renderer/document_subresource_filter.h" - -#include <climits> - -#include "base/logging.h" -#include "base/strings/string_piece.h" -#include "base/strings/string_util.h" -#include "base/trace_event/trace_event.h" -#include "components/subresource_filter/core/common/first_party_origin.h" -#include "components/subresource_filter/core/common/memory_mapped_ruleset.h" -#include "components/subresource_filter/core/common/scoped_timers.h" -#include "components/subresource_filter/core/common/time_measurements.h" -#include "third_party/WebKit/public/platform/WebURL.h" - -namespace subresource_filter { - -namespace { - -proto::ElementType ToElementType( - blink::WebURLRequest::RequestContext request_context) { - switch (request_context) { - case blink::WebURLRequest::RequestContextAudio: - case blink::WebURLRequest::RequestContextVideo: - case blink::WebURLRequest::RequestContextTrack: - return proto::ELEMENT_TYPE_MEDIA; - case blink::WebURLRequest::RequestContextBeacon: - case blink::WebURLRequest::RequestContextPing: - return proto::ELEMENT_TYPE_PING; - case blink::WebURLRequest::RequestContextEmbed: - case blink::WebURLRequest::RequestContextObject: - case blink::WebURLRequest::RequestContextPlugin: - return proto::ELEMENT_TYPE_OBJECT; - case blink::WebURLRequest::RequestContextEventSource: - case blink::WebURLRequest::RequestContextFetch: - case blink::WebURLRequest::RequestContextXMLHttpRequest: - return proto::ELEMENT_TYPE_XMLHTTPREQUEST; - case blink::WebURLRequest::RequestContextFavicon: - case blink::WebURLRequest::RequestContextImage: - case blink::WebURLRequest::RequestContextImageSet: - return proto::ELEMENT_TYPE_IMAGE; - case blink::WebURLRequest::RequestContextFont: - return proto::ELEMENT_TYPE_FONT; - case blink::WebURLRequest::RequestContextFrame: - case blink::WebURLRequest::RequestContextForm: - case blink::WebURLRequest::RequestContextHyperlink: - case blink::WebURLRequest::RequestContextIframe: - case blink::WebURLRequest::RequestContextInternal: - case blink::WebURLRequest::RequestContextLocation: - return proto::ELEMENT_TYPE_SUBDOCUMENT; - case blink::WebURLRequest::RequestContextScript: - case blink::WebURLRequest::RequestContextServiceWorker: - case blink::WebURLRequest::RequestContextSharedWorker: - return proto::ELEMENT_TYPE_SCRIPT; - case blink::WebURLRequest::RequestContextStyle: - case blink::WebURLRequest::RequestContextXSLT: - return proto::ELEMENT_TYPE_STYLESHEET; - - case blink::WebURLRequest::RequestContextPrefetch: - case blink::WebURLRequest::RequestContextSubresource: - return proto::ELEMENT_TYPE_OTHER; - - case blink::WebURLRequest::RequestContextCSPReport: - case blink::WebURLRequest::RequestContextDownload: - case blink::WebURLRequest::RequestContextImport: - case blink::WebURLRequest::RequestContextManifest: - case blink::WebURLRequest::RequestContextUnspecified: - default: - return proto::ELEMENT_TYPE_UNSPECIFIED; - } -} - -} // namespace - -DocumentSubresourceFilter::DocumentSubresourceFilter( - ActivationLevel activation_level, - bool measure_performance, - const scoped_refptr<const MemoryMappedRuleset>& ruleset, - const std::vector<GURL>& ancestor_document_urls, - const base::Closure& first_disallowed_load_callback) - : activation_level_(activation_level), - measure_performance_(measure_performance), - ruleset_(ruleset), - ruleset_matcher_(ruleset_->data(), ruleset_->length()), - first_disallowed_load_callback_(first_disallowed_load_callback) { - TRACE_EVENT1("loader", "DocumentSubresourceFilter::DocumentSubresourceFilter", - "document_url", ancestor_document_urls.empty() - ? std::string() - : ancestor_document_urls[0].spec()); - - SCOPED_UMA_HISTOGRAM_MICRO_TIMER( - "SubresourceFilter.DocumentLoad.Activation.WallDuration"); - SCOPED_UMA_HISTOGRAM_MICRO_THREAD_TIMER( - "SubresourceFilter.DocumentLoad.Activation.CPUDuration"); - - DCHECK_NE(activation_level_, ActivationLevel::DISABLED); - DCHECK(ruleset); - - url::Origin parent_document_origin; - for (auto iter = ancestor_document_urls.rbegin(), - rend = ancestor_document_urls.rend(); - iter != rend; ++iter) { - const GURL& document_url(*iter); - if (ruleset_matcher_.ShouldDisableFilteringForDocument( - document_url, parent_document_origin, - proto::ACTIVATION_TYPE_DOCUMENT)) { - filtering_disabled_for_document_ = true; - return; - } - // TODO(pkalinnikov): Match several activation types in a batch. - generic_blocking_rules_disabled_ = - generic_blocking_rules_disabled_ || - ruleset_matcher_.ShouldDisableFilteringForDocument( - document_url, parent_document_origin, - proto::ACTIVATION_TYPE_GENERICBLOCK); - - // TODO(pkalinnikov): Think about avoiding this conversion. - parent_document_origin = url::Origin(document_url); - } - - url::Origin document_origin = std::move(parent_document_origin); - document_origin_.reset(new FirstPartyOrigin(std::move(document_origin))); -} - -DocumentSubresourceFilter::~DocumentSubresourceFilter() = default; - -bool DocumentSubresourceFilter::allowLoad( - const blink::WebURL& resourceUrl, - blink::WebURLRequest::RequestContext request_context) { - TRACE_EVENT1("loader", "DocumentSubresourceFilter::allowLoad", "url", - resourceUrl.string().utf8()); - - auto wall_duration_timer = ScopedTimers::StartIf( - measure_performance_ && ScopedThreadTimers::IsSupported(), - [this](base::TimeDelta delta) { - statistics_.evaluation_total_wall_duration += delta; - UMA_HISTOGRAM_MICRO_TIMES( - "SubresourceFilter.SubresourceLoad.Evaluation.WallDuration", delta); - }); - auto cpu_duration_timer = ScopedThreadTimers::StartIf( - measure_performance_, [this](base::TimeDelta delta) { - statistics_.evaluation_total_cpu_duration += delta; - UMA_HISTOGRAM_MICRO_TIMES( - "SubresourceFilter.SubresourceLoad.Evaluation.CPUDuration", delta); - }); - - ++statistics_.num_loads_total; - - if (filtering_disabled_for_document_) - return true; - - if (resourceUrl.protocolIs(url::kDataScheme)) - return true; - - ++statistics_.num_loads_evaluated; - DCHECK(document_origin_); - if (ruleset_matcher_.ShouldDisallowResourceLoad( - GURL(resourceUrl), *document_origin_, ToElementType(request_context), - generic_blocking_rules_disabled_)) { - ++statistics_.num_loads_matching_rules; - if (activation_level_ == ActivationLevel::ENABLED) { - if (!first_disallowed_load_callback_.is_null()) { - DCHECK_EQ(statistics_.num_loads_disallowed, 0); - first_disallowed_load_callback_.Run(); - first_disallowed_load_callback_.Reset(); - } - ++statistics_.num_loads_disallowed; - return false; - } - } - return true; -} - -} // namespace subresource_filter
diff --git a/components/subresource_filter/content/renderer/document_subresource_filter.h b/components/subresource_filter/content/renderer/document_subresource_filter.h deleted file mode 100644 index d09ac3b..0000000 --- a/components/subresource_filter/content/renderer/document_subresource_filter.h +++ /dev/null
@@ -1,92 +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 COMPONENTS_SUBRESOURCE_FILTER_CONTENT_RENDERER_DOCUMENT_SUBRESOURCE_FILTER_H_ -#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_RENDERER_DOCUMENT_SUBRESOURCE_FILTER_H_ - -#include <stddef.h> - -#include <vector> - -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/time/time.h" -#include "components/subresource_filter/content/common/document_load_statistics.h" -#include "components/subresource_filter/core/common/activation_level.h" -#include "components/subresource_filter/core/common/indexed_ruleset.h" -#include "third_party/WebKit/public/platform/WebDocumentSubresourceFilter.h" -#include "url/gurl.h" -#include "url/origin.h" - -namespace subresource_filter { - -class FirstPartyOrigin; -class MemoryMappedRuleset; - -// Performs filtering of subresource loads in the scope of a given document. -class DocumentSubresourceFilter - : public blink::WebDocumentSubresourceFilter, - public base::SupportsWeakPtr<DocumentSubresourceFilter> { - public: - // Constructs a new filter that will: - // -- Operate at the prescribed |activation_level|, which must be either - // ActivationLevel::DRYRUN or ActivationLevel::ENABLED. In the former - // case filtering will be performed but no loads will be disallowed. - // -- Hold a reference to and use |ruleset| for its entire lifetime. - // -- Expect |ancestor_document_urls| to be the URLs of documents loaded into - // nested frames, starting with the current frame and ending with the main - // frame. This provides the context for evaluating domain-specific rules. - // -- Invoke |first_disallowed_load_callback|, if it is non-null, on the - // first disallowed subresource load. - DocumentSubresourceFilter( - ActivationLevel activation_level, - bool measure_performance, - const scoped_refptr<const MemoryMappedRuleset>& ruleset, - const std::vector<GURL>& ancestor_document_urls, - const base::Closure& first_disallowed_load_callback); - ~DocumentSubresourceFilter() override; - - const DocumentLoadStatistics& statistics() const { return statistics_; } - - // blink::WebDocumentSubresourceFilter: - bool allowLoad(const blink::WebURL& resourceUrl, - blink::WebURLRequest::RequestContext) override; - - private: - const ActivationLevel activation_level_; - const bool measure_performance_; - - scoped_refptr<const MemoryMappedRuleset> ruleset_; - IndexedRulesetMatcher ruleset_matcher_; - - // Note: Equals nullptr iff |filtering_disabled_for_document_|. - std::unique_ptr<FirstPartyOrigin> document_origin_; - - base::Closure first_disallowed_load_callback_; - - // Even when subresource filtering is activated at the page level by the - // |activation_level| passed into the constructor, the current document or - // ancestors thereof may still match special filtering rules that specifically - // disable the application of other types of rules on these documents. See - // proto::ActivationType for details. - // - // Indicates whether the document is subject to a whitelist rule with DOCUMENT - // activation type. - bool filtering_disabled_for_document_ = false; - - // Indicates whether the document is subject to a whitelist rule with - // GENERICBLOCK activation type. Undefined if - // |filtering_disabled_for_document_|. - bool generic_blocking_rules_disabled_ = false; - - DocumentLoadStatistics statistics_; - - DISALLOW_COPY_AND_ASSIGN(DocumentSubresourceFilter); -}; - -} // namespace subresource_filter - -#endif // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_RENDERER_DOCUMENT_SUBRESOURCE_FILTER_H_
diff --git a/components/subresource_filter/content/renderer/document_subresource_filter_unittest.cc b/components/subresource_filter/content/renderer/document_subresource_filter_unittest.cc deleted file mode 100644 index f3e78c7..0000000 --- a/components/subresource_filter/content/renderer/document_subresource_filter_unittest.cc +++ /dev/null
@@ -1,142 +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. - -#include "components/subresource_filter/content/renderer/document_subresource_filter.h" - -#include "base/bind.h" -#include "base/callback.h" -#include "base/files/file.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/strings/string_piece.h" -#include "components/subresource_filter/core/common/memory_mapped_ruleset.h" -#include "components/subresource_filter/core/common/test_ruleset_creator.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/WebKit/public/platform/WebURL.h" -#include "third_party/WebKit/public/platform/WebURLRequest.h" -#include "url/gurl.h" - -namespace subresource_filter { - -namespace { - -const char kTestAlphaURL[] = "http://example.com/alpha"; -const char kTestAlphaDataURI[] = "data:text/plain,alpha"; -const char kTestBetaURL[] = "http://example.com/beta"; - -const char kTestAlphaURLPathSuffix[] = "alpha"; - -class TestCallbackReceiver { - public: - TestCallbackReceiver() = default; - base::Closure closure() { - return base::Bind(&TestCallbackReceiver::CallbackMethod, - base::Unretained(this)); - } - size_t callback_count() const { return callback_count_; } - - private: - void CallbackMethod() { ++callback_count_; } - - size_t callback_count_ = 0; - - DISALLOW_COPY_AND_ASSIGN(TestCallbackReceiver); -}; - -} // namespace - -class DocumentSubresourceFilterTest : public ::testing::Test { - public: - DocumentSubresourceFilterTest() {} - - protected: - void SetUp() override { - ASSERT_NO_FATAL_FAILURE( - SetTestRulesetToDisallowURLsWithPathSuffix(kTestAlphaURLPathSuffix)); - } - - void SetTestRulesetToDisallowURLsWithPathSuffix(base::StringPiece suffix) { - testing::TestRulesetPair test_ruleset_pair; - ASSERT_NO_FATAL_FAILURE( - test_ruleset_creator_.CreateRulesetToDisallowURLsWithPathSuffix( - suffix, &test_ruleset_pair)); - ruleset_ = new MemoryMappedRuleset( - testing::TestRuleset::Open(test_ruleset_pair.indexed)); - } - - const MemoryMappedRuleset* ruleset() { return ruleset_.get(); } - - private: - testing::TestRulesetCreator test_ruleset_creator_; - scoped_refptr<const MemoryMappedRuleset> ruleset_; - - DISALLOW_COPY_AND_ASSIGN(DocumentSubresourceFilterTest); -}; - -TEST_F(DocumentSubresourceFilterTest, DryRun) { - blink::WebURLRequest::RequestContext request_context = - blink::WebURLRequest::RequestContextImage; - TestCallbackReceiver first_disallowed_load_callback_receiver; - DocumentSubresourceFilter filter( - ActivationLevel::DRYRUN, true, ruleset(), std::vector<GURL>(), - first_disallowed_load_callback_receiver.closure()); - EXPECT_TRUE(filter.allowLoad(GURL(kTestAlphaURL), request_context)); - EXPECT_TRUE(filter.allowLoad(GURL(kTestAlphaDataURI), request_context)); - EXPECT_TRUE(filter.allowLoad(GURL(kTestBetaURL), request_context)); - - const auto& statistics = filter.statistics(); - EXPECT_EQ(3, statistics.num_loads_total); - EXPECT_EQ(2, statistics.num_loads_evaluated); - EXPECT_EQ(1, statistics.num_loads_matching_rules); - EXPECT_EQ(0, statistics.num_loads_disallowed); - - EXPECT_EQ(0u, first_disallowed_load_callback_receiver.callback_count()); -} - -TEST_F(DocumentSubresourceFilterTest, Enabled) { - auto test_impl = [this](bool measure_performance) { - blink::WebURLRequest::RequestContext request_context = - blink::WebURLRequest::RequestContextImage; - DocumentSubresourceFilter filter(ActivationLevel::ENABLED, - measure_performance, ruleset(), - std::vector<GURL>(), base::Closure()); - EXPECT_FALSE(filter.allowLoad(GURL(kTestAlphaURL), request_context)); - EXPECT_TRUE(filter.allowLoad(GURL(kTestAlphaDataURI), request_context)); - EXPECT_TRUE(filter.allowLoad(GURL(kTestBetaURL), request_context)); - - const auto& statistics = filter.statistics(); - EXPECT_EQ(3, statistics.num_loads_total); - EXPECT_EQ(2, statistics.num_loads_evaluated); - EXPECT_EQ(1, statistics.num_loads_matching_rules); - EXPECT_EQ(1, statistics.num_loads_disallowed); - - if (!measure_performance) { - EXPECT_TRUE(statistics.evaluation_total_cpu_duration.is_zero()); - EXPECT_TRUE(statistics.evaluation_total_wall_duration.is_zero()); - } - // Otherwise, don't expect |total_duration| to be non-zero, although it - // practically is (when timer is supported). - }; - - test_impl(true /* measure_performance */); - test_impl(false /* measure_performance */); -} - -TEST_F(DocumentSubresourceFilterTest, - CallbackFiredExactlyOnceAfterFirstDisallowedLoad) { - blink::WebURLRequest::RequestContext request_context = - blink::WebURLRequest::RequestContextImage; - TestCallbackReceiver first_disallowed_load_callback_receiver; - DocumentSubresourceFilter filter( - ActivationLevel::ENABLED, true, ruleset(), std::vector<GURL>(), - first_disallowed_load_callback_receiver.closure()); - EXPECT_TRUE(filter.allowLoad(GURL(kTestAlphaDataURI), request_context)); - EXPECT_EQ(0u, first_disallowed_load_callback_receiver.callback_count()); - EXPECT_FALSE(filter.allowLoad(GURL(kTestAlphaURL), request_context)); - EXPECT_EQ(1u, first_disallowed_load_callback_receiver.callback_count()); - EXPECT_FALSE(filter.allowLoad(GURL(kTestAlphaURL), request_context)); - EXPECT_EQ(1u, first_disallowed_load_callback_receiver.callback_count()); -} - -} // namespace subresource_filter
diff --git a/components/subresource_filter/content/renderer/subresource_filter_agent.cc b/components/subresource_filter/content/renderer/subresource_filter_agent.cc index b2982b6..6b08edc 100644 --- a/components/subresource_filter/content/renderer/subresource_filter_agent.cc +++ b/components/subresource_filter/content/renderer/subresource_filter_agent.cc
@@ -8,8 +8,8 @@ #include "base/memory/ref_counted.h" #include "base/metrics/histogram_macros.h" #include "base/time/time.h" +#include "components/subresource_filter/content/common/document_subresource_filter.h" #include "components/subresource_filter/content/common/subresource_filter_messages.h" -#include "components/subresource_filter/content/renderer/document_subresource_filter.h" #include "components/subresource_filter/content/renderer/unverified_ruleset_dealer.h" #include "components/subresource_filter/core/common/memory_mapped_ruleset.h" #include "components/subresource_filter/core/common/scoped_timers.h" @@ -77,8 +77,10 @@ } void SubresourceFilterAgent::RecordHistogramsOnLoadCommitted() { + // Note: ActivationLevel used to be called ActivationState, the legacy name is + // kept for the histogram. UMA_HISTOGRAM_ENUMERATION( - "SubresourceFilter.DocumentLoad.ActivationLevel", + "SubresourceFilter.DocumentLoad.ActivationState", static_cast<int>(activation_level_for_provisional_load_), static_cast<int>(ActivationLevel::LAST) + 1); @@ -131,18 +133,16 @@ delete this; } -void SubresourceFilterAgent::DidStartProvisionalLoad() { +void SubresourceFilterAgent::DidStartProvisionalLoad( + blink::WebDataSource* data_source) { // With PlzNavigate, DidStartProvisionalLoad and DidCommitProvisionalLoad will // both be called in response to the one commit IPC from the browser. That // means that they will come after OnActivateForProvisionalLoad. So we have to // have extra logic to check that the response to OnActivateForProvisionalLoad // isn't removed in that case. - blink::WebDataSource* ds = - render_frame() ? render_frame()->GetWebFrame()->provisionalDataSource() - : nullptr; if (!content::IsBrowserSideNavigationEnabled() || - (!ds || - static_cast<GURL>(ds->getRequest().url()) != + (!data_source || + static_cast<GURL>(data_source->getRequest().url()) != url_for_provisional_load_)) { activation_level_for_provisional_load_ = ActivationLevel::DISABLED; measure_performance_ = false; @@ -164,15 +164,22 @@ RecordHistogramsOnLoadCommitted(); if (activation_level_for_provisional_load_ != ActivationLevel::DISABLED && ruleset_dealer_->IsRulesetFileAvailable()) { - base::Closure first_disallowed_load_callback( - base::Bind(&SubresourceFilterAgent:: - SignalFirstSubresourceDisallowedForCommittedLoad, - AsWeakPtr())); + base::OnceClosure first_disallowed_load_callback( + base::BindOnce(&SubresourceFilterAgent:: + SignalFirstSubresourceDisallowedForCommittedLoad, + AsWeakPtr())); + + auto ruleset = ruleset_dealer_->GetRuleset(); + DCHECK(ruleset); + ActivationState activation_state = ComputeActivationState( + activation_level_for_provisional_load_, measure_performance_, + ancestor_document_urls, ruleset.get()); + DCHECK(!ancestor_document_urls.empty()); std::unique_ptr<DocumentSubresourceFilter> filter( new DocumentSubresourceFilter( - activation_level_for_provisional_load_, measure_performance_, - ruleset_dealer_->GetRuleset(), ancestor_document_urls, - first_disallowed_load_callback)); + url::Origin(ancestor_document_urls[0]), activation_state, + std::move(ruleset), std::move(first_disallowed_load_callback))); + filter_for_last_committed_load_ = filter->AsWeakPtr(); SetSubresourceFilterForCommittedLoad(std::move(filter)); }
diff --git a/components/subresource_filter/content/renderer/subresource_filter_agent.h b/components/subresource_filter/content/renderer/subresource_filter_agent.h index 9a8d01a..75533a0d2 100644 --- a/components/subresource_filter/content/renderer/subresource_filter_agent.h +++ b/components/subresource_filter/content/renderer/subresource_filter_agent.h
@@ -70,7 +70,7 @@ // content::RenderFrameObserver: void OnDestruct() override; - void DidStartProvisionalLoad() override; + void DidStartProvisionalLoad(blink::WebDataSource* data_source) override; void DidCommitProvisionalLoad(bool is_new_navigation, bool is_same_page_navigation) override; void DidFinishLoad() override;
diff --git a/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc b/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc index 7a8b9bd0..0329363 100644 --- a/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc +++ b/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
@@ -80,7 +80,7 @@ constexpr const char kDocumentLoadRulesetIsAvailable[] = "SubresourceFilter.DocumentLoad.RulesetIsAvailable"; constexpr const char kDocumentLoadActivationLevel[] = - "SubresourceFilter.DocumentLoad.ActivationLevel"; + "SubresourceFilter.DocumentLoad.ActivationState"; constexpr const char kSubresourcesEvaluated[] = "SubresourceFilter.DocumentLoad.NumSubresourceLoads.Evaluated"; constexpr const char kSubresourcesTotal[] = @@ -121,13 +121,13 @@ } void StartLoadWithoutSettingActivationLevel() { - agent_as_rfo()->DidStartProvisionalLoad(); + agent_as_rfo()->DidStartProvisionalLoad(nullptr); agent_as_rfo()->DidCommitProvisionalLoad( true /* is_new_navigation */, false /* is_same_page_navigation */); } void PerformSamePageNavigationWithoutSettingActivationLevel() { - agent_as_rfo()->DidStartProvisionalLoad(); + agent_as_rfo()->DidStartProvisionalLoad(nullptr); agent_as_rfo()->DidCommitProvisionalLoad( true /* is_new_navigation */, true /* is_same_page_navigation */); // No DidFinishLoad is called in this case. @@ -135,7 +135,7 @@ void StartLoadAndSetActivationLevel(ActivationLevel activation_level, bool measure_performance = false) { - agent_as_rfo()->DidStartProvisionalLoad(); + agent_as_rfo()->DidStartProvisionalLoad(nullptr); EXPECT_TRUE(agent_as_rfo()->OnMessageReceived( SubresourceFilterMsg_ActivateForProvisionalLoad( 0, activation_level, GURL(), measure_performance))); @@ -170,11 +170,21 @@ EXPECT_CALL(*agent(), SendDocumentLoadStatistics(::testing::_)); } - void ExpectLoadAllowed(base::StringPiece url_spec, bool allowed) { + void ExpectLoadPolicy( + base::StringPiece url_spec, + blink::WebDocumentSubresourceFilter::LoadPolicy expected_policy) { blink::WebURL url = GURL(url_spec); blink::WebURLRequest::RequestContext request_context = blink::WebURLRequest::RequestContextImage; - EXPECT_EQ(allowed, agent()->filter()->allowLoad(url, request_context)); + blink::WebDocumentSubresourceFilter::LoadPolicy actual_policy = + agent()->filter()->getLoadPolicy(url, request_context); + EXPECT_EQ(expected_policy, actual_policy); + + // If the load policy indicated the load was filtered, simulate a filtered + // load callback. In production, this will be called in FrameFetchContext, + // but we simulate the call here. + if (actual_policy == blink::WebDocumentSubresourceFilter::Disallow) + agent()->filter()->reportDisallowedLoad(); } SubresourceFilterAgentUnderTest* agent() { return agent_.get(); } @@ -273,8 +283,9 @@ ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent())); ExpectSignalAboutFirstSubresourceDisallowed(); - ExpectLoadAllowed(kTestFirstURL, false); - ExpectLoadAllowed(kTestSecondURL, true); + ExpectLoadPolicy(kTestFirstURL, + blink::WebDocumentSubresourceFilter::Disallow); + ExpectLoadPolicy(kTestSecondURL, blink::WebDocumentSubresourceFilter::Allow); ExpectDocumentLoadStatisticsSent(); FinishLoad(); @@ -282,8 +293,9 @@ ExpectNoSubresourceFilterGetsInjected(); ExpectNoSignalAboutFirstSubresourceDisallowed(); PerformSamePageNavigationWithoutSettingActivationLevel(); - ExpectLoadAllowed(kTestFirstURL, false); - ExpectLoadAllowed(kTestSecondURL, true); + ExpectLoadPolicy(kTestFirstURL, + blink::WebDocumentSubresourceFilter::Disallow); + ExpectLoadPolicy(kTestSecondURL, blink::WebDocumentSubresourceFilter::Allow); ExpectNoSubresourceFilterGetsInjected(); StartLoadWithoutSettingActivationLevel(); @@ -313,11 +325,14 @@ ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent())); ExpectSignalAboutFirstSubresourceDisallowed(); - ExpectLoadAllowed(kTestFirstURL, false); + ExpectLoadPolicy(kTestFirstURL, + blink::WebDocumentSubresourceFilter::Disallow); ExpectNoSignalAboutFirstSubresourceDisallowed(); - ExpectLoadAllowed(kTestFirstURL, false); + ExpectLoadPolicy(kTestFirstURL, + blink::WebDocumentSubresourceFilter::Disallow); ExpectNoSignalAboutFirstSubresourceDisallowed(); - ExpectLoadAllowed(kTestSecondURL, true); + ExpectLoadPolicy(kTestSecondURL, + blink::WebDocumentSubresourceFilter::Allow); ExpectDocumentLoadStatisticsSent(); FinishLoad(); @@ -327,9 +342,11 @@ ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent())); ExpectNoSignalAboutFirstSubresourceDisallowed(); - ExpectLoadAllowed(kTestSecondURL, true); + ExpectLoadPolicy(kTestSecondURL, + blink::WebDocumentSubresourceFilter::Allow); ExpectSignalAboutFirstSubresourceDisallowed(); - ExpectLoadAllowed(kTestFirstURL, false); + ExpectLoadPolicy(kTestFirstURL, + blink::WebDocumentSubresourceFilter::Disallow); ExpectDocumentLoadStatisticsSent(); FinishLoad(); @@ -369,8 +386,9 @@ SetTestRulesetToDisallowURLsWithPathSuffix(kTestSecondURLPathSuffix)); ExpectSignalAboutFirstSubresourceDisallowed(); - ExpectLoadAllowed(kTestFirstURL, false); - ExpectLoadAllowed(kTestSecondURL, true); + ExpectLoadPolicy(kTestFirstURL, + blink::WebDocumentSubresourceFilter::Disallow); + ExpectLoadPolicy(kTestSecondURL, blink::WebDocumentSubresourceFilter::Allow); ExpectDocumentLoadStatisticsSent(); FinishLoad(); @@ -379,8 +397,9 @@ ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent())); ExpectSignalAboutFirstSubresourceDisallowed(); - ExpectLoadAllowed(kTestFirstURL, true); - ExpectLoadAllowed(kTestSecondURL, false); + ExpectLoadPolicy(kTestFirstURL, blink::WebDocumentSubresourceFilter::Allow); + ExpectLoadPolicy(kTestSecondURL, + blink::WebDocumentSubresourceFilter::Disallow); ExpectDocumentLoadStatisticsSent(); FinishLoad(); } @@ -394,11 +413,11 @@ ASSERT_NO_FATAL_FAILURE( SetTestRulesetToDisallowURLsWithPathSuffix(kTestBothURLsPathSuffix)); ExpectNoSubresourceFilterGetsInjected(); - agent_as_rfo()->DidStartProvisionalLoad(); + agent_as_rfo()->DidStartProvisionalLoad(nullptr); EXPECT_TRUE(agent_as_rfo()->OnMessageReceived( SubresourceFilterMsg_ActivateForProvisionalLoad( 0, ActivationLevel::ENABLED, GURL(), true))); - agent_as_rfo()->DidStartProvisionalLoad(); + agent_as_rfo()->DidStartProvisionalLoad(nullptr); agent_as_rfo()->DidCommitProvisionalLoad(true /* is_new_navigation */, false /* is_same_page_navigation */); FinishLoad(); @@ -415,9 +434,11 @@ // In dry-run mode, loads to the first URL should be recorded as // `MatchedRules`, but still be allowed to proceed and not recorded as // `Disallowed`. - ExpectLoadAllowed(kTestFirstURL, true); - ExpectLoadAllowed(kTestFirstURL, true); - ExpectLoadAllowed(kTestSecondURL, true); + ExpectLoadPolicy(kTestFirstURL, + blink::WebDocumentSubresourceFilter::WouldDisallow); + ExpectLoadPolicy(kTestFirstURL, + blink::WebDocumentSubresourceFilter::WouldDisallow); + ExpectLoadPolicy(kTestSecondURL, blink::WebDocumentSubresourceFilter::Allow); ExpectDocumentLoadStatisticsSent(); FinishLoad(); @@ -445,10 +466,12 @@ ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent())); ExpectSignalAboutFirstSubresourceDisallowed(); - ExpectLoadAllowed(kTestFirstURL, false); + ExpectLoadPolicy(kTestFirstURL, + blink::WebDocumentSubresourceFilter::Disallow); ExpectNoSignalAboutFirstSubresourceDisallowed(); - ExpectLoadAllowed(kTestFirstURL, false); - ExpectLoadAllowed(kTestSecondURL, true); + ExpectLoadPolicy(kTestFirstURL, + blink::WebDocumentSubresourceFilter::Disallow); + ExpectLoadPolicy(kTestSecondURL, blink::WebDocumentSubresourceFilter::Allow); ExpectDocumentLoadStatisticsSent(); FinishLoad(); @@ -456,9 +479,10 @@ StartLoadAndSetActivationLevel(ActivationLevel::ENABLED); ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent())); - ExpectLoadAllowed(kTestSecondURL, true); + ExpectLoadPolicy(kTestSecondURL, blink::WebDocumentSubresourceFilter::Allow); ExpectSignalAboutFirstSubresourceDisallowed(); - ExpectLoadAllowed(kTestFirstURL, false); + ExpectLoadPolicy(kTestFirstURL, + blink::WebDocumentSubresourceFilter::Disallow); ExpectDocumentLoadStatisticsSent(); FinishLoad(); } @@ -473,8 +497,13 @@ auto filter = agent()->TakeFilter(); ResetAgent(); - EXPECT_FALSE(filter->allowLoad(GURL(kTestFirstURL), - blink::WebURLRequest::RequestContextImage)); + + // The filter has been disconnected from the agent, so a call to + // reportDisallowedLoad() should not signal a first resource disallowed call + // to the agent, nor should it cause a crash. + ExpectNoSignalAboutFirstSubresourceDisallowed(); + + filter->reportDisallowedLoad(); } } // namespace subresource_filter
diff --git a/components/subresource_filter/core/browser/subresource_filter_features.cc b/components/subresource_filter/core/browser/subresource_filter_features.cc index 9d319f3..f141869 100644 --- a/components/subresource_filter/core/browser/subresource_filter_features.cc +++ b/components/subresource_filter/core/browser/subresource_filter_features.cc
@@ -33,6 +33,8 @@ "social_engineering_ads_interstitial"; const char kActivationListPhishingInterstitial[] = "phishing_interstitial"; +const char kRulesetFlavorParameterName[] = "ruleset_flavor"; + const char kPerformanceMeasurementRateParameterName[] = "performance_measurement_rate"; @@ -93,4 +95,10 @@ false /* default value */); } +std::string GetRulesetFlavor() { + return variations::GetVariationParamValueByFeature( + subresource_filter::kSafeBrowsingSubresourceFilter, + subresource_filter::kRulesetFlavorParameterName); +} + } // namespace subresource_filter
diff --git a/components/subresource_filter/core/browser/subresource_filter_features.h b/components/subresource_filter/core/browser/subresource_filter_features.h index 4594651..a73408d 100644 --- a/components/subresource_filter/core/browser/subresource_filter_features.h +++ b/components/subresource_filter/core/browser/subresource_filter_features.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_SUBRESOURCE_FILTER_SUBRESOURCE_FILTER_FEATURES_H_ -#define COMPONENTS_SUBRESOURCE_FILTER_SUBRESOURCE_FILTER_FEATURES_H_ +#ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_FEATURES_H_ +#define COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_FEATURES_H_ #include "base/feature_list.h" #include "components/subresource_filter/core/common/activation_level.h" @@ -30,6 +30,8 @@ extern const char kActivationListSocialEngineeringAdsInterstitial[]; extern const char kActivationListPhishingInterstitial[]; +extern const char kRulesetFlavorParameterName[]; + extern const char kPerformanceMeasurementRateParameterName[]; extern const char kSuppressNotificationsParameterName[]; @@ -59,6 +61,10 @@ // should be suppressed in the UI. bool ShouldSuppressNotifications(); +// Returns the ruleset flavor, or the empty string if the default ruleset should +// be used. +std::string GetRulesetFlavor(); + } // namespace subresource_filter -#endif // COMPONENTS_SUBRESOURCE_FILTER_SUBRESOURCE_FILTER_FEATURES_H_ +#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_FEATURES_H_
diff --git a/components/subresource_filter/core/common/activation_state.h b/components/subresource_filter/core/common/activation_state.h index fc84569..a591ed6 100644 --- a/components/subresource_filter/core/common/activation_state.h +++ b/components/subresource_filter/core/common/activation_state.h
@@ -12,6 +12,23 @@ // Encompasses all details of whether/how subresource filtering should be // activated in a given frame in the frame hierarchy. struct ActivationState { + ActivationState() = default; + + explicit ActivationState(ActivationLevel activation_level) + : activation_level(activation_level) {} + + bool operator==(const ActivationState& rhs) const { + return activation_level == rhs.activation_level && + filtering_disabled_for_document == + rhs.filtering_disabled_for_document && + (filtering_disabled_for_document || + generic_blocking_rules_disabled == + rhs.generic_blocking_rules_disabled) && + measure_performance == rhs.measure_performance; + } + + bool operator!=(const ActivationState& rhs) const { return !operator==(rhs); } + // The degree to which subresource filtering is activated for the page load. ActivationLevel activation_level = ActivationLevel::DISABLED;
diff --git a/components/subresource_filter/core/common/test_ruleset_utils.cc b/components/subresource_filter/core/common/test_ruleset_utils.cc index 081a4a1..e97548ec 100644 --- a/components/subresource_filter/core/common/test_ruleset_utils.cc +++ b/components/subresource_filter/core/common/test_ruleset_utils.cc
@@ -19,15 +19,22 @@ return rule; } -proto::UrlRule CreateWhitelistRuleForDocument(base::StringPiece pattern) { +proto::UrlRule CreateWhitelistRuleForDocument( + base::StringPiece pattern, + int32_t activation_types, + std::vector<std::string> domains) { proto::UrlRule rule; + rule.set_semantics(proto::RULE_SEMANTICS_WHITELIST); rule.set_source_type(proto::SOURCE_TYPE_ANY); - rule.set_element_types(proto::ELEMENT_TYPE_ALL); + rule.set_activation_types(activation_types); + + for (std::string& domain : domains) { + rule.add_domains()->set_domain(std::move(domain)); + } + rule.set_url_pattern_type(proto::URL_PATTERN_TYPE_SUBSTRING); rule.set_anchor_left(proto::ANCHOR_TYPE_NONE); rule.set_anchor_right(proto::ANCHOR_TYPE_NONE); - rule.set_semantics(proto::RULE_SEMANTICS_WHITELIST); - rule.set_activation_types(proto::ACTIVATION_TYPE_DOCUMENT); rule.set_url_pattern(pattern.as_string()); return rule; }
diff --git a/components/subresource_filter/core/common/test_ruleset_utils.h b/components/subresource_filter/core/common/test_ruleset_utils.h index 97c2452..ef70865 100644 --- a/components/subresource_filter/core/common/test_ruleset_utils.h +++ b/components/subresource_filter/core/common/test_ruleset_utils.h
@@ -5,6 +5,10 @@ #ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_TEST_RULESET_UTILS_H_ #define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_TEST_RULESET_UTILS_H_ +#include <stdint.h> +#include <string> +#include <vector> + #include "base/strings/string_piece.h" #include "components/subresource_filter/core/common/proto/rules.pb.h" @@ -13,7 +17,10 @@ proto::UrlRule CreateSuffixRule(base::StringPiece suffix); -proto::UrlRule CreateWhitelistRuleForDocument(base::StringPiece pattern); +proto::UrlRule CreateWhitelistRuleForDocument( + base::StringPiece pattern, + int32_t activation_types = proto::ACTIVATION_TYPE_DOCUMENT, + std::vector<std::string> domains = std::vector<std::string>()); } // namespace testing } // namespace subresource_filter
diff --git a/components/sync/driver/proxy_data_type_controller.cc b/components/sync/driver/proxy_data_type_controller.cc index 0bc9a75..08d3a953 100644 --- a/components/sync/driver/proxy_data_type_controller.cc +++ b/components/sync/driver/proxy_data_type_controller.cc
@@ -6,6 +6,8 @@ #include "base/memory/ptr_util.h" #include "base/values.h" +#include "components/sync/engine/model_safe_worker.h" +#include "components/sync/engine/model_type_configurer.h" #include "components/sync/model/sync_merge_result.h" namespace syncer { @@ -22,7 +24,14 @@ } void ProxyDataTypeController::BeforeLoadModels( - ModelTypeConfigurer* configurer) {} + ModelTypeConfigurer* configurer) { + // Proxy type doesn't need to be registered with ModelTypeRegistry as it + // doesn't need update handler, client doesn't expect updates of this type + // from the server. We still need to register proxy type because + // AddClientConfigParamsToMessage decides the value of tabs_datatype_enabled + // based on presence of proxy types in the set of enabled types. + configurer->RegisterDirectoryDataType(type(), GROUP_PASSIVE); +} void ProxyDataTypeController::LoadModels( const ModelLoadCallback& model_load_callback) { @@ -62,7 +71,9 @@ ModelTypeConfigurer* configurer) {} void ProxyDataTypeController::DeactivateDataType( - ModelTypeConfigurer* configurer) {} + ModelTypeConfigurer* configurer) { + configurer->UnregisterDirectoryDataType(type()); +} void ProxyDataTypeController::GetAllNodes(const AllNodesCallback& callback) { callback.Run(type(), base::MakeUnique<base::ListValue>());
diff --git a/components/test/android/browsertests_apk/components_browser_tests_jni_onload.cc b/components/test/android/browsertests_apk/components_browser_tests_jni_onload.cc index df59922..a2ec78b44 100644 --- a/components/test/android/browsertests_apk/components_browser_tests_jni_onload.cc +++ b/components/test/android/browsertests_apk/components_browser_tests_jni_onload.cc
@@ -4,6 +4,7 @@ #include "base/android/base_jni_registrar.h" #include "base/android/jni_android.h" +#include "base/android/library_loader/library_loader_hooks.h" #include "base/bind.h" #include "content/public/app/content_jni_onload.h" #include "content/public/app/content_main.h" @@ -19,7 +20,9 @@ testing::android::RegisterNativeTestJNI(env); } -bool Init() { +bool NativeInit() { + if (!content::android::OnJNIOnLoadInit()) + return false; content::SetContentMainDelegate(new content::ShellMainDelegate()); return true; } @@ -28,12 +31,10 @@ // This is called by the VM when the shared library is first loaded. JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { - std::vector<base::android::RegisterCallback> register_callbacks; - register_callbacks.push_back(base::Bind(&RegisterJNI)); - std::vector<base::android::InitCallback> init_callbacks; - init_callbacks.push_back(base::Bind(&Init)); - if (!content::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks) || - !content::android::OnJNIOnLoadInit(init_callbacks)) { + base::android::InitVM(vm); + JNIEnv* env = base::android::AttachCurrentThread(); + if (!content::android::OnJNIOnLoadRegisterJNI(env) || !RegisterJNI(env) || + !NativeInit()) { return -1; } return JNI_VERSION_1_4;
diff --git a/components/test/data/password_manager/OWNERS b/components/test/data/password_manager/OWNERS index 17d27ac..acc1360 100644 --- a/components/test/data/password_manager/OWNERS +++ b/components/test/data/password_manager/OWNERS
@@ -1,3 +1,5 @@ gcasto@chromium.org mkwst@chromium.org vabr@chromium.org + +# COMPONENT: UI>Browser>Passwords
diff --git a/components/test_runner/OWNERS b/components/test_runner/OWNERS index a8a2075..7609fea 100644 --- a/components/test_runner/OWNERS +++ b/components/test_runner/OWNERS
@@ -5,3 +5,5 @@ rbyers@chromium.org tkent@chromium.org tommyw@chromium.org + +# COMPONENT: Test>Layout
diff --git a/components/test_runner/event_sender.cc b/components/test_runner/event_sender.cc index 7f38826..01f8a5e9 100644 --- a/components/test_runner/event_sender.cc +++ b/components/test_runner/event_sender.cc
@@ -11,6 +11,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/command_line.h" +#include "base/files/file_path.h" #include "base/logging.h" #include "base/macros.h" #include "base/strings/string16.h" @@ -26,6 +27,8 @@ #include "gin/handle.h" #include "gin/object_template_builder.h" #include "gin/wrappable.h" +#include "net/base/filename_util.h" +#include "third_party/WebKit/public/platform/URLConversion.h" #include "third_party/WebKit/public/platform/WebCoalescedInputEvent.h" #include "third_party/WebKit/public/platform/WebGestureEvent.h" #include "third_party/WebKit/public/platform/WebKeyboardEvent.h" @@ -62,6 +65,7 @@ using blink::WebString; using blink::WebTouchEvent; using blink::WebTouchPoint; +using blink::WebURL; using blink::WebVector; using blink::WebView; @@ -1890,16 +1894,28 @@ if (current_drag_data_.isNull()) return; - WebString filename; WebVector<WebDragData::Item> items = current_drag_data_.items(); for (size_t i = 0; i < items.size(); ++i) { if (items[i].storageType == WebDragData::Item::StorageTypeBinaryData) { - filename = items[i].title; - break; + WebURL url = items[i].binaryDataSourceURL; + WebString filename_extension = items[i].binaryDataFilenameExtension; + WebString content_disposition = items[i].binaryDataContentDisposition; + base::FilePath filename = + net::GenerateFileName(url, content_disposition.utf8(), + std::string(), // referrer_charset + std::string(), // suggested_name + std::string(), // mime_type + std::string()); // default_name +#if defined(OS_WIN) + filename = filename.ReplaceExtension(filename_extension.utf16()); +#else + filename = filename.ReplaceExtension(filename_extension.utf8()); +#endif + delegate()->PrintMessage(std::string("Filename being dragged: ") + + filename.AsUTF8Unsafe() + "\n"); + return; } } - delegate()->PrintMessage(std::string("Filename being dragged: ") + - filename.utf8().data() + "\n"); } void EventSender::GestureFlingCancel() { @@ -2236,22 +2252,6 @@ time_offset_ms_ += milliseconds; } -void EventSender::GetOptionalTouchArgs(gin::Arguments* args, - bool& moved_beyond_slop_region, - uint32_t& unique_touch_event_id) { - moved_beyond_slop_region = false; - if(!args->PeekNext().IsEmpty() && args->PeekNext()->IsString()) { - std::string arg; - if (args->GetNext(&arg) && arg == "movedBeyondSlopRegion") - moved_beyond_slop_region = true; - else - args->ThrowError(); - } - - unique_touch_event_id = GetUniqueTouchEventId(args); - return; -} - uint32_t EventSender::GetUniqueTouchEventId(gin::Arguments* args) { uint32_t unique_touch_event_id; if(!args->PeekNext().IsEmpty() && args->GetNext(&unique_touch_event_id)) @@ -2262,9 +2262,7 @@ void EventSender::SendCurrentTouchEvent(WebInputEvent::Type type, gin::Arguments* args) { - bool moved_beyond_slop_region; - uint32_t unique_touch_event_id; - GetOptionalTouchArgs(args, moved_beyond_slop_region, unique_touch_event_id); + uint32_t unique_touch_event_id = GetUniqueTouchEventId(args); DCHECK_GT(static_cast<unsigned>(WebTouchEvent::kTouchesLengthCap), touch_points_.size()); @@ -2275,7 +2273,7 @@ touch_event.dispatchType = touch_cancelable_ ? WebInputEvent::Blocking : WebInputEvent::EventNonBlocking; - touch_event.movedBeyondSlopRegion = moved_beyond_slop_region; + touch_event.movedBeyondSlopRegion = true; touch_event.uniqueTouchEventId = unique_touch_event_id; touch_event.touchesLength = touch_points_.size(); for (size_t i = 0; i < touch_points_.size(); ++i) @@ -2689,7 +2687,8 @@ mainFrameWidget()->dragTargetDrop(current_drag_data_, client_point, screen_point, event->modifiers()); } else { - mainFrameWidget()->dragTargetDragLeave(); + mainFrameWidget()->dragTargetDragLeave(blink::WebPoint(), + blink::WebPoint()); } current_drag_data_.reset(); mainFrameWidget()->dragSourceEndedAt(client_point, screen_point,
diff --git a/components/test_runner/event_sender.h b/components/test_runner/event_sender.h index d8f30b1..344ad8e8 100644 --- a/components/test_runner/event_sender.h +++ b/components/test_runner/event_sender.h
@@ -177,9 +177,6 @@ void DoLeapForward(int milliseconds); - void GetOptionalTouchArgs(gin::Arguments* args, - bool& moved_beyond_slop_region, - uint32_t& unique_touch_event_id); uint32_t GetUniqueTouchEventId(gin::Arguments* args); void SendCurrentTouchEvent(blink::WebInputEvent::Type, gin::Arguments* args);
diff --git a/components/test_runner/mock_web_document_subresource_filter.cc b/components/test_runner/mock_web_document_subresource_filter.cc index bdd1e53..c8397ee 100644 --- a/components/test_runner/mock_web_document_subresource_filter.cc +++ b/components/test_runner/mock_web_document_subresource_filter.cc
@@ -18,7 +18,8 @@ MockWebDocumentSubresourceFilter::~MockWebDocumentSubresourceFilter() {} -bool MockWebDocumentSubresourceFilter::allowLoad( +blink::WebDocumentSubresourceFilter::LoadPolicy +MockWebDocumentSubresourceFilter::getLoadPolicy( const blink::WebURL& resource_url, blink::WebURLRequest::RequestContext /* ignored */) { const std::string resource_path(GURL(resource_url).path()); @@ -27,7 +28,11 @@ [&resource_path](const std::string& suffix) { return base::EndsWith(resource_path, suffix, base::CompareCase::SENSITIVE); - }) == disallowed_path_suffixes_.end(); + }) == disallowed_path_suffixes_.end() + ? Allow + : Disallow; } +void MockWebDocumentSubresourceFilter::reportDisallowedLoad() {} + } // namespace test_runner
diff --git a/components/test_runner/mock_web_document_subresource_filter.h b/components/test_runner/mock_web_document_subresource_filter.h index 22c9f36..e1334e0 100644 --- a/components/test_runner/mock_web_document_subresource_filter.h +++ b/components/test_runner/mock_web_document_subresource_filter.h
@@ -26,8 +26,9 @@ ~MockWebDocumentSubresourceFilter() override; // blink::WebDocumentSubresourceFilter: - bool allowLoad(const blink::WebURL& resource_url, - blink::WebURLRequest::RequestContext) override; + LoadPolicy getLoadPolicy(const blink::WebURL& resource_url, + blink::WebURLRequest::RequestContext) override; + void reportDisallowedLoad() override; private: std::vector<std::string> disallowed_path_suffixes_;
diff --git a/components/test_runner/test_interfaces.cc b/components/test_runner/test_interfaces.cc index 29ec4b4..994ae7a7 100644 --- a/components/test_runner/test_interfaces.cc +++ b/components/test_runner/test_interfaces.cc
@@ -18,8 +18,8 @@ #include "components/test_runner/test_runner.h" #include "components/test_runner/text_input_controller.h" #include "components/test_runner/web_view_test_proxy.h" +#include "third_party/WebKit/public/platform/WebCache.h" #include "third_party/WebKit/public/platform/WebURL.h" -#include "third_party/WebKit/public/web/WebCache.h" #include "third_party/WebKit/public/web/WebKit.h" #include "third_party/WebKit/public/web/WebView.h"
diff --git a/components/test_runner/web_frame_test_client.cc b/components/test_runner/web_frame_test_client.cc index 75c5d8824..11a8eda 100644 --- a/components/test_runner/web_frame_test_client.cc +++ b/components/test_runner/web_frame_test_client.cc
@@ -29,6 +29,7 @@ #include "third_party/WebKit/public/platform/WebURLRequest.h" #include "third_party/WebKit/public/platform/WebURLResponse.h" #include "third_party/WebKit/public/web/WebConsoleMessage.h" +#include "third_party/WebKit/public/web/WebDataSource.h" #include "third_party/WebKit/public/web/WebElement.h" #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" @@ -412,16 +413,25 @@ } } -void WebFrameTestClient::didStartProvisionalLoad(blink::WebLocalFrame* frame) { - test_runner()->tryToSetTopLoadingFrame(frame); +void WebFrameTestClient::didStartProvisionalLoad( + blink::WebDataSource* data_source) { + // PlzNavigate + // A provisional load notification is received when a frame navigation is + // sent to the browser. We don't want to log it again during commit. + if (delegate_->IsNavigationInitiatedByRenderer(data_source->getRequest())) + return; + + test_runner()->tryToSetTopLoadingFrame( + web_frame_test_proxy_base_->web_frame()); if (test_runner()->shouldDumpFrameLoadCallbacks()) { - PrintFrameDescription(delegate_, frame); + PrintFrameDescription(delegate_, web_frame_test_proxy_base_->web_frame()); delegate_->PrintMessage(" - didStartProvisionalLoadForFrame\n"); } if (test_runner()->shouldDumpUserGestureInFrameLoadCallbacks()) { - PrintFrameuserGestureStatus(delegate_, frame, + PrintFrameuserGestureStatus(delegate_, + web_frame_test_proxy_base_->web_frame(), " - in didStartProvisionalLoadForFrame\n"); } }
diff --git a/components/test_runner/web_frame_test_client.h b/components/test_runner/web_frame_test_client.h index 27cb35a..68dc7f7c 100644 --- a/components/test_runner/web_frame_test_client.h +++ b/components/test_runner/web_frame_test_client.h
@@ -61,7 +61,7 @@ const blink::WebString& suggested_name, bool replaces_current_history_item) override; void loadErrorPage(int reason) override; - void didStartProvisionalLoad(blink::WebLocalFrame* frame) override; + void didStartProvisionalLoad(blink::WebDataSource* data_source) override; void didReceiveServerRedirectForProvisionalLoad( blink::WebLocalFrame* frame) override; void didFailProvisionalLoad(blink::WebLocalFrame* frame,
diff --git a/components/test_runner/web_frame_test_proxy.h b/components/test_runner/web_frame_test_proxy.h index ac44430..4f31867 100644 --- a/components/test_runner/web_frame_test_proxy.h +++ b/components/test_runner/web_frame_test_proxy.h
@@ -96,9 +96,9 @@ replaces_current_history_item); } - void didStartProvisionalLoad(blink::WebLocalFrame* frame) override { - test_client()->didStartProvisionalLoad(frame); - Base::didStartProvisionalLoad(frame); + void didStartProvisionalLoad(blink::WebDataSource* data_source) override { + test_client()->didStartProvisionalLoad(data_source); + Base::didStartProvisionalLoad(data_source); } void didReceiveServerRedirectForProvisionalLoad(
diff --git a/components/toolbar/BUILD.gn b/components/toolbar/BUILD.gn index ec98fd4..08478b45 100644 --- a/components/toolbar/BUILD.gn +++ b/components/toolbar/BUILD.gn
@@ -3,50 +3,27 @@ # found in the LICENSE file. import("//build/config/ui.gni") +import("//ui/vector_icons/vector_icons.gni") -action("aggregate_vector_icons") { - visibility = [ ":*" ] - - script = "//ui/gfx/vector_icons/aggregate_vector_icons.py" +aggregate_vector_icons("toolbar_vector_icons") { + icon_directory = "vector_icons" icons = [ # TODO(estade): this is the same as ui/gfx/vector_icons/business.icon. Use # that one instead once it's been updated from VectorIconId to VectorIcon. - "vector_icons/business.icon", - "vector_icons/http.1x.icon", - "vector_icons/http.icon", - "vector_icons/https_invalid.1x.icon", - "vector_icons/https_invalid.icon", - "vector_icons/https_valid.1x.icon", - "vector_icons/https_valid.icon", - "vector_icons/https_valid_in_chip.1x.icon", - "vector_icons/https_valid_in_chip.icon", - "vector_icons/product.1x.icon", - "vector_icons/product.icon", - "vector_icons/star_active.icon", - "vector_icons/star.icon", - ] - - output_cc = "$target_gen_dir/vector_icons.cc" - output_h = "$target_gen_dir/vector_icons.h" - - inputs = icons - inputs += [ - "vector_icons/vector_icons.cc.template", - "vector_icons/vector_icons.h.template", - ] - outputs = [ - output_cc, - output_h, - ] - - response_file_contents = rebase_path(icons, root_build_dir) - - args = [ - "--working_directory=" + rebase_path("./vector_icons"), - "--file_list={{response_file_name}}", - "--output_cc=" + rebase_path(output_cc, root_build_dir), - "--output_h=" + rebase_path(output_h, root_build_dir), + "business.icon", + "http.1x.icon", + "http.icon", + "https_invalid.1x.icon", + "https_invalid.icon", + "https_valid.1x.icon", + "https_valid.icon", + "https_valid_in_chip.1x.icon", + "https_valid_in_chip.icon", + "product.1x.icon", + "product.icon", + "star_active.icon", + "star.icon", ] } @@ -73,8 +50,8 @@ ] if (!is_android && !is_ios) { - sources += get_target_outputs(":aggregate_vector_icons") - deps += [ ":aggregate_vector_icons" ] + sources += get_target_outputs(":toolbar_vector_icons") + deps += [ ":toolbar_vector_icons" ] } }
diff --git a/components/translate/content/browser/content_translate_driver.cc b/components/translate/content/browser/content_translate_driver.cc index ed585f3..9eb5694 100644 --- a/components/translate/content/browser/content_translate_driver.cc +++ b/components/translate/content/browser/content_translate_driver.cc
@@ -15,6 +15,7 @@ #include "content/public/browser/navigation_controller.h" #include "content/public/browser/navigation_details.h" #include "content/public/browser/navigation_entry.h" +#include "content/public/browser/navigation_handle.h" #include "content/public/browser/page_navigator.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" @@ -211,17 +212,18 @@ 0)); } -void ContentTranslateDriver::DidNavigateAnyFrame( - content::RenderFrameHost* render_frame_host, - const content::LoadCommittedDetails& details, - const content::FrameNavigateParams& params) { +void ContentTranslateDriver::DidFinishNavigation( + content::NavigationHandle* navigation_handle) { + if (!navigation_handle->HasCommitted()) + return; + // Let the LanguageState clear its state. const bool reload = - ui::PageTransitionCoreTypeIs(details.entry->GetTransitionType(), - ui::PAGE_TRANSITION_RELOAD) || - details.type == content::NAVIGATION_TYPE_SAME_PAGE; + navigation_handle->GetReloadType() != content::ReloadType::NONE || + navigation_handle->IsSamePage(); translate_manager_->GetLanguageState().DidNavigate( - details.is_in_page, details.is_main_frame, reload); + navigation_handle->IsSamePage(), navigation_handle->IsInMainFrame(), + reload); } void ContentTranslateDriver::OnPageAway(int page_seq_no) {
diff --git a/components/translate/content/browser/content_translate_driver.h b/components/translate/content/browser/content_translate_driver.h index a6a9faa..fdf415e 100644 --- a/components/translate/content/browser/content_translate_driver.h +++ b/components/translate/content/browser/content_translate_driver.h
@@ -96,9 +96,8 @@ // content::WebContentsObserver implementation. void NavigationEntryCommitted( const content::LoadCommittedDetails& load_details) override; - void DidNavigateAnyFrame(content::RenderFrameHost* render_frame_host, - const content::LoadCommittedDetails& details, - const content::FrameNavigateParams& params) override; + void DidFinishNavigation( + content::NavigationHandle* navigation_handle) override; void OnPageTranslated(bool cancelled, const std::string& original_lang,
diff --git a/components/web_cache/renderer/DEPS b/components/web_cache/renderer/DEPS index c001589f..0672fbe 100644 --- a/components/web_cache/renderer/DEPS +++ b/components/web_cache/renderer/DEPS
@@ -3,5 +3,5 @@ "+content/public/renderer", "+mojo/public", "+services/service_manager/public/cpp", - "+third_party/WebKit/public/web", + "+third_party/WebKit/public/platform/WebCache.h", ]
diff --git a/components/web_cache/renderer/web_cache_impl.cc b/components/web_cache/renderer/web_cache_impl.cc index 936d020..664c4ff 100644 --- a/components/web_cache/renderer/web_cache_impl.cc +++ b/components/web_cache/renderer/web_cache_impl.cc
@@ -10,7 +10,7 @@ #include "base/numerics/safe_conversions.h" #include "content/public/renderer/render_thread.h" #include "services/service_manager/public/cpp/interface_registry.h" -#include "third_party/WebKit/public/web/WebCache.h" +#include "third_party/WebKit/public/platform/WebCache.h" namespace web_cache {
diff --git a/content/app/android/content_jni_onload.cc b/content/app/android/content_jni_onload.cc index 67a596d4..15f89d2d 100644 --- a/content/app/android/content_jni_onload.cc +++ b/content/app/android/content_jni_onload.cc
@@ -7,6 +7,7 @@ #include <vector> #include "base/android/base_jni_onload.h" +#include "base/android/jni_android.h" #include "base/android/library_loader/library_loader_hooks.h" #include "base/bind.h" #include "content/app/android/library_loader_hooks.h" @@ -15,32 +16,20 @@ namespace content { namespace android { -namespace { +bool OnJNIOnLoadRegisterJNI(JNIEnv* env) { + if (!base::android::OnJNIOnLoadRegisterJNI(env)) + return false; -bool RegisterJNI(JNIEnv* env) { return content::EnsureJniRegistered(env); } -bool Init() { +bool OnJNIOnLoadInit() { + if (!base::android::OnJNIOnLoadInit()) + return false; + base::android::SetLibraryLoadedHook(&content::LibraryLoaded); return true; } -} // namespace - - -bool OnJNIOnLoadRegisterJNI( - JavaVM* vm, - std::vector<base::android::RegisterCallback> callbacks) { - callbacks.push_back(base::Bind(&RegisterJNI)); - return base::android::OnJNIOnLoadRegisterJNI(vm, callbacks); -} - -bool OnJNIOnLoadInit( - std::vector<base::android::InitCallback> callbacks) { - callbacks.push_back(base::Bind(&Init)); - return base::android::OnJNIOnLoadInit(callbacks); -} - } // namespace android } // namespace content
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 4d43f9a..ee3c5e6 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -76,7 +76,6 @@ "//device/geolocation/public/interfaces", "//device/nfc:mojo_bindings", "//device/power_save_blocker", - "//device/screen_orientation/public/interfaces", "//device/sensors", "//device/vibration", "//device/vr", @@ -1209,8 +1208,6 @@ "resolve_proxy_msg_helper.h", "resource_context_impl.cc", "resource_context_impl.h", - "screen_orientation/screen_orientation.cc", - "screen_orientation/screen_orientation.h", "screen_orientation/screen_orientation_delegate_win.cc", "screen_orientation/screen_orientation_delegate_win.h", "service_manager/merge_dictionary.cc", @@ -1802,6 +1799,7 @@ deps -= [ "//device/battery" ] deps += [ "//content/public/android:jni", + "//device/screen_orientation/public/interfaces", "//media", "//media/capture/content/android", "//media/capture/video/android",
diff --git a/content/browser/accessibility/accessibility_ui.cc b/content/browser/accessibility/accessibility_ui.cc index 2d409c6..2042326f 100644 --- a/content/browser/accessibility/accessibility_ui.cc +++ b/content/browser/accessibility/accessibility_ui.cc
@@ -331,9 +331,10 @@ base::ASCIIToUTF16("*"), AccessibilityTreeFormatter::Filter::ALLOW)); formatter->SetFilters(filters); - formatter->FormatAccessibilityTree( - web_contents->GetRootBrowserAccessibilityManager()->GetRoot(), - &accessibility_contents_utf16); + auto* ax_mgr = web_contents->GetOrCreateRootBrowserAccessibilityManager(); + DCHECK(ax_mgr); + formatter->FormatAccessibilityTree(ax_mgr->GetRoot(), + &accessibility_contents_utf16); result->Set("tree", new base::StringValue( base::UTF16ToUTF8(accessibility_contents_utf16)));
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc index 392db7b..9d97ff3 100644 --- a/content/browser/android/content_view_core_impl.cc +++ b/content/browser/android/content_view_core_impl.cc
@@ -1403,23 +1403,6 @@ ->OnOrientationChange(); } -void ContentViewCoreImpl::ExtractSmartClipData(JNIEnv* env, - const JavaParamRef<jobject>& obj, - jint x, - jint y, - jint width, - jint height) { - gfx::Rect rect( - static_cast<int>(x / dpi_scale()), - static_cast<int>(y / dpi_scale()), - static_cast<int>((width > 0 && width < dpi_scale()) ? - 1 : (int)(width / dpi_scale())), - static_cast<int>((height > 0 && height < dpi_scale()) ? - 1 : (int)(height / dpi_scale()))); - GetWebContents()->Send(new ViewMsg_ExtractSmartClipData( - GetWebContents()->GetRenderViewHost()->GetRoutingID(), rect)); -} - jint ContentViewCoreImpl::GetCurrentRenderProcessId( JNIEnv* env, const JavaParamRef<jobject>& obj) { @@ -1525,21 +1508,6 @@ Java_ContentViewCore_hidePopupsAndPreserveSelection(env, obj); } -void ContentViewCoreImpl::OnSmartClipDataExtracted( - const base::string16& text, - const base::string16& html, - const gfx::Rect& clip_rect) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); - if (obj.is_null()) - return; - ScopedJavaLocalRef<jstring> jtext = ConvertUTF16ToJavaString(env, text); - ScopedJavaLocalRef<jstring> jhtml = ConvertUTF16ToJavaString(env, html); - ScopedJavaLocalRef<jobject> clip_rect_object(CreateJavaRect(env, clip_rect)); - Java_ContentViewCore_onSmartClipDataExtracted(env, obj, jtext, jhtml, - clip_rect_object); -} - void ContentViewCoreImpl::WebContentsDestroyed() { WebContentsViewAndroid* wcva = static_cast<WebContentsViewAndroid*>( static_cast<WebContentsImpl*>(web_contents())->GetView());
diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h index 18d55d4..603fd441 100644 --- a/content/browser/android/content_view_core_impl.h +++ b/content/browser/android/content_view_core_impl.h
@@ -259,13 +259,6 @@ const base::android::JavaParamRef<jstring>& textTrackTextShadow, const base::android::JavaParamRef<jstring>& textTrackTextSize); - void ExtractSmartClipData(JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj, - jint x, - jint y, - jint width, - jint height); - void SetBackgroundOpaque(JNIEnv* env, const base::android::JavaParamRef<jobject>& jobj, jboolean opaque); @@ -293,10 +286,6 @@ void HidePopupsAndPreserveSelection(); - void OnSmartClipDataExtracted(const base::string16& text, - const base::string16& html, - const gfx::Rect& clip_rect); - // Creates a popup menu with |items|. // |multiple| defines if it should support multi-select. // If not |multiple|, |selected_item| sets the initially selected item.
diff --git a/content/browser/browser_plugin/browser_plugin_guest.cc b/content/browser/browser_plugin/browser_plugin_guest.cc index 8ac87c8..7b85e54 100644 --- a/content/browser/browser_plugin/browser_plugin_guest.cc +++ b/content/browser/browser_plugin/browser_plugin_guest.cc
@@ -865,7 +865,7 @@ break; case blink::WebDragStatusLeave: embedder->DragLeftGuest(this); - widget->DragTargetDragLeave(); + widget->DragTargetDragLeave(gfx::Point(), gfx::Point()); ignore_dragged_url_ = true; break; case blink::WebDragStatusDrop:
diff --git a/content/browser/browser_thread_impl.cc b/content/browser/browser_thread_impl.cc index 2b89f6d..895fba21 100644 --- a/content/browser/browser_thread_impl.cc +++ b/content/browser/browser_thread_impl.cc
@@ -5,6 +5,7 @@ #include "content/browser/browser_thread_impl.h" #include <string> +#include <utility> #include "base/atomicops.h" #include "base/bind.h" @@ -538,10 +539,10 @@ // static bool BrowserThread::PostBlockingPoolTaskAndReply( const tracked_objects::Location& from_here, - const base::Closure& task, - const base::Closure& reply) { + base::Closure task, + base::Closure reply) { return g_globals.Get().blocking_pool->PostTaskAndReply( - from_here, task, reply); + from_here, std::move(task), std::move(reply)); } // static @@ -653,13 +654,12 @@ } // static -bool BrowserThread::PostTaskAndReply( - ID identifier, - const tracked_objects::Location& from_here, - const base::Closure& task, - const base::Closure& reply) { +bool BrowserThread::PostTaskAndReply(ID identifier, + const tracked_objects::Location& from_here, + base::Closure task, + base::Closure reply) { return GetTaskRunnerForThread(identifier) - ->PostTaskAndReply(from_here, task, reply); + ->PostTaskAndReply(from_here, std::move(task), std::move(reply)); } // static
diff --git a/content/browser/devtools/devtools_manager_unittest.cc b/content/browser/devtools/devtools_manager_unittest.cc index 4f97266..09c7c11 100644 --- a/content/browser/devtools/devtools_manager_unittest.cc +++ b/content/browser/devtools/devtools_manager_unittest.cc
@@ -251,6 +251,7 @@ bool Activate() override { return false; }; void Reload() override { }; bool Close() override { return false; }; + base::TimeTicks GetLastActivityTime() override { return base::TimeTicks(); } void SendMessageToBackend(const std::string& message) override { recordEvent(std::string("SendMessageToBackend.") + message);
diff --git a/content/browser/devtools/forwarding_agent_host.cc b/content/browser/devtools/forwarding_agent_host.cc index 808759d..5859034e 100644 --- a/content/browser/devtools/forwarding_agent_host.cc +++ b/content/browser/devtools/forwarding_agent_host.cc
@@ -76,4 +76,8 @@ return delegate_->Close(); } +base::TimeTicks ForwardingAgentHost::GetLastActivityTime() { + return delegate_->GetLastActivityTime(); +} + } // content
diff --git a/content/browser/devtools/forwarding_agent_host.h b/content/browser/devtools/forwarding_agent_host.h index 36263cd..02469b5 100644 --- a/content/browser/devtools/forwarding_agent_host.h +++ b/content/browser/devtools/forwarding_agent_host.h
@@ -45,6 +45,7 @@ bool Activate() override; void Reload() override; bool Close() override; + base::TimeTicks GetLastActivityTime() override; std::unique_ptr<DevToolsExternalAgentProxyDelegate> delegate_; std::string type_;
diff --git a/content/browser/frame_host/navigation_handle_impl.h b/content/browser/frame_host/navigation_handle_impl.h index c092ac8..74b629e 100644 --- a/content/browser/frame_host/navigation_handle_impl.h +++ b/content/browser/frame_host/navigation_handle_impl.h
@@ -314,6 +314,11 @@ searchable_form_encoding_ = encoding; } + void set_response_headers_for_testing( + scoped_refptr<net::HttpResponseHeaders> response_headers) { + response_headers_ = response_headers; + } + private: friend class NavigationHandleImplTest;
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc index f50df19..0c34b760 100644 --- a/content/browser/frame_host/navigator_impl.cc +++ b/content/browser/frame_host/navigator_impl.cc
@@ -1243,11 +1243,20 @@ bool has_browser_initiated_pending_entry = pending_entry && !pending_entry->is_renderer_initiated(); + // PlzNavigate + // A pending navigation entry is created in OnBeginNavigation(). The renderer + // sends a provisional load notification after that. We don't want to create + // a duplicate navigation entry here. + bool renderer_provisional_load_to_pending_url = + pending_entry && pending_entry->is_renderer_initiated() && + (pending_entry->GetURL() == url); + // If there is a transient entry, creating a new pending entry will result // in deleting it, which leads to inconsistent state. bool has_transient_entry = !!controller_->GetTransientEntry(); - if (!has_browser_initiated_pending_entry && !has_transient_entry) { + if (!has_browser_initiated_pending_entry && !has_transient_entry && + !renderer_provisional_load_to_pending_url) { std::unique_ptr<NavigationEntryImpl> entry = NavigationEntryImpl::FromNavigationEntry( controller_->CreateNavigationEntry(
diff --git a/content/browser/frame_host/render_frame_host_delegate.cc b/content/browser/frame_host/render_frame_host_delegate.cc index 7314dcbc..cb8545c 100644 --- a/content/browser/frame_host/render_frame_host_delegate.cc +++ b/content/browser/frame_host/render_frame_host_delegate.cc
@@ -82,11 +82,6 @@ return nullptr; } -ScreenOrientationProvider* -RenderFrameHostDelegate::GetScreenOrientationProvider() { - return nullptr; -} - bool RenderFrameHostDelegate::ShouldRouteMessageEvent( RenderFrameHost* target_rfh, SiteInstance* source_site_instance) const {
diff --git a/content/browser/frame_host/render_frame_host_delegate.h b/content/browser/frame_host/render_frame_host_delegate.h index 77a62aac..33f79445 100644 --- a/content/browser/frame_host/render_frame_host_delegate.h +++ b/content/browser/frame_host/render_frame_host_delegate.h
@@ -47,7 +47,6 @@ class PageState; class RenderFrameHost; class RenderFrameHostImpl; -class ScreenOrientationProvider; class SessionStorageNamespace; class WebContents; struct AXEventNotificationDetails; @@ -187,9 +186,6 @@ // Gets the WakeLockServiceContext associated with this delegate. virtual device::WakeLockServiceContext* GetWakeLockServiceContext(); - // Gets the ScreenOrientationProvider associated with this delegate. - virtual ScreenOrientationProvider* GetScreenOrientationProvider(); - // Notification that the frame wants to go into fullscreen mode. // |origin| represents the origin of the frame that requests fullscreen. virtual void EnterFullscreenMode(const GURL& origin) {}
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index 6551608..c241a26fa 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -720,6 +720,8 @@ OnJavaScriptExecuteResponse) IPC_MESSAGE_HANDLER(FrameHostMsg_VisualStateResponse, OnVisualStateResponse) + IPC_MESSAGE_HANDLER(FrameHostMsg_SmartClipDataExtracted, + OnSmartClipDataExtracted) IPC_MESSAGE_HANDLER_DELAY_REPLY(FrameHostMsg_RunJavaScriptMessage, OnRunJavaScriptMessage) IPC_MESSAGE_HANDLER_DELAY_REPLY(FrameHostMsg_RunBeforeUnloadConfirm, @@ -1551,7 +1553,11 @@ for (const auto& iter : ax_tree_snapshot_callbacks_) iter.second.Run(ui::AXTreeUpdate()); + for (const auto& iter : smart_clip_callbacks_) + iter.second.Run(base::string16(), base::string16()); + ax_tree_snapshot_callbacks_.clear(); + smart_clip_callbacks_.clear(); javascript_callbacks_.clear(); visual_state_callbacks_.clear(); form_field_data_callbacks_.clear(); @@ -1652,6 +1658,26 @@ } } +void RenderFrameHostImpl::RequestSmartClipExtract(SmartClipCallback callback, + gfx::Rect rect) { + static uint32_t next_id = 1; + uint32_t key = next_id++; + Send(new FrameMsg_ExtractSmartClipData(routing_id_, key, rect)); + smart_clip_callbacks_.insert(std::make_pair(key, callback)); +} + +void RenderFrameHostImpl::OnSmartClipDataExtracted(uint32_t id, + base::string16 text, + base::string16 html) { + auto it = smart_clip_callbacks_.find(id); + if (it != smart_clip_callbacks_.end()) { + it->second.Run(text, html); + smart_clip_callbacks_.erase(it); + } else { + NOTREACHED() << "Received smartclip data response for unknown request"; + } +} + void RenderFrameHostImpl::OnVisualStateResponse(uint64_t id) { auto it = visual_state_callbacks_.find(id); if (it != visual_state_callbacks_.end()) {
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h index e904d8f..ff7dec19 100644 --- a/content/browser/frame_host/render_frame_host_impl.h +++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -48,6 +48,7 @@ #include "third_party/WebKit/public/web/WebTextDirection.h" #include "third_party/WebKit/public/web/WebTreeScopeType.h" #include "ui/accessibility/ax_node_data.h" +#include "ui/base/mojo/window_open_disposition.mojom.h" #include "ui/base/page_transition_types.h" class GURL; @@ -119,6 +120,8 @@ using AXTreeSnapshotCallback = base::Callback<void( const ui::AXTreeUpdate&)>; + using SmartClipCallback = base::Callback<void(const base::string16& text, + const base::string16& html)>; // An accessibility reset is only allowed to prevent very rare corner cases // or race conditions where the browser and renderer get out of sync. If @@ -474,6 +477,9 @@ // renderer process to change the accessibility mode. void UpdateAccessibilityMode(); + // Samsung Galaxy Note-specific "smart clip" stylus text getter. + void RequestSmartClipExtract(SmartClipCallback callback, gfx::Rect rect); + // Request a one-time snapshot of the accessibility tree without changing // the accessibility mode. void RequestAXTreeSnapshot(AXTreeSnapshotCallback callback); @@ -734,6 +740,9 @@ void OnAccessibilitySnapshotResponse( int callback_id, const AXContentTreeUpdate& snapshot); + void OnSmartClipDataExtracted(uint32_t id, + base::string16 text, + base::string16 html); void OnToggleFullscreen(bool enter_fullscreen); void OnDidStartLoading(bool to_different_document); void OnDidStopLoading(); @@ -1058,6 +1067,9 @@ // accessibility tree snapshot calls created by RequestAXTreeSnapshot. std::map<int, AXTreeSnapshotCallback> ax_tree_snapshot_callbacks_; + // Samsung Galaxy Note-specific "smart clip" stylus text getter. + std::map<uint32_t, SmartClipCallback> smart_clip_callbacks_; + // Callback when an event is received, for testing. base::Callback<void(RenderFrameHostImpl*, ui::AXEvent, int)> accessibility_testing_callback_;
diff --git a/content/browser/gpu/gpu_internals_ui.cc b/content/browser/gpu/gpu_internals_ui.cc index cc18c39d..987f0fa 100644 --- a/content/browser/gpu/gpu_internals_ui.cc +++ b/content/browser/gpu/gpu_internals_ui.cc
@@ -144,14 +144,6 @@ "Optimus", new base::FundamentalValue(gpu_info.optimus))); basic_info->Append(NewDescriptionValuePair( "AMD switchable", new base::FundamentalValue(gpu_info.amd_switchable))); - if (gpu_info.lenovo_dcute) { - basic_info->Append(NewDescriptionValuePair( - "Lenovo dCute", new base::FundamentalValue(true))); - } - if (gpu_info.display_link_version.IsValid()) { - basic_info->Append(NewDescriptionValuePair( - "DisplayLink Version", gpu_info.display_link_version.GetString())); - } #if defined(OS_WIN) std::string compositor = ui::win::IsAeroGlassEnabled() ? "Aero Glass" : "none";
diff --git a/content/browser/loader/resource_scheduler.cc b/content/browser/loader/resource_scheduler.cc index 6973687..6d68cf1c 100644 --- a/content/browser/loader/resource_scheduler.cc +++ b/content/browser/loader/resource_scheduler.cc
@@ -354,7 +354,9 @@ using_spdy_proxy_(false), in_flight_delayable_count_(0), total_layout_blocking_count_(0), - priority_requests_delayable_(priority_requests_delayable) {} + priority_requests_delayable_(priority_requests_delayable), + has_pending_start_task_(false), + weak_ptr_factory_(this) {} ~Client() {} @@ -377,10 +379,9 @@ EraseInFlightRequest(request); // Removing this request may have freed up another to load. - LoadAnyStartablePendingRequests( - has_html_body_ - ? RequestStartTrigger::COMPLETION_POST_BODY - : RequestStartTrigger::COMPLETION_PRE_BODY); + ScheduleLoadAnyStartablePendingRequests( + has_html_body_ ? RequestStartTrigger::COMPLETION_POST_BODY + : RequestStartTrigger::COMPLETION_PRE_BODY); } } @@ -453,7 +454,7 @@ if (new_priority_params.priority > old_priority_params.priority) { // Check if this request is now able to load at its new priority. - LoadAnyStartablePendingRequests( + ScheduleLoadAnyStartablePendingRequests( RequestStartTrigger::REQUEST_REPRIORITIZED); } } @@ -719,6 +720,24 @@ return START_REQUEST; } + // It is common for a burst of messages to come from the renderer which + // trigger starting pending requests. Naively, this would result in O(n*m) + // behavior for n pending requests and m <= n messages, as + // LoadAnyStartablePendingRequest is O(n) for n pending requests. To solve + // this, just post a task to the end of the queue to call the method, + // coalescing the m messages into a single call to + // LoadAnyStartablePendingRequests. + // TODO(csharrison): Reconsider this if IPC batching becomes an easy to use + // pattern. + void ScheduleLoadAnyStartablePendingRequests(RequestStartTrigger trigger) { + if (has_pending_start_task_) + return; + has_pending_start_task_ = true; + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&Client::LoadAnyStartablePendingRequests, + weak_ptr_factory_.GetWeakPtr(), trigger)); + } + void LoadAnyStartablePendingRequests(RequestStartTrigger trigger) { // We iterate through all the pending requests, starting with the highest // priority one. For each entry, one of three things can happen: @@ -728,6 +747,7 @@ // the previous request still in the list. // 3) We do not start the request, same as above, but StartRequest() tells // us there's no point in checking any further requests. + has_pending_start_task_ = false; RequestQueue::NetQueue::iterator request_iter = pending_requests_.GetNextHighestIterator(); @@ -771,6 +791,10 @@ // True if requests to servers that support priorities (e.g., H2/QUIC) can // be delayed. bool priority_requests_delayable_; + + bool has_pending_start_task_; + + base::WeakPtrFactory<ResourceScheduler::Client> weak_ptr_factory_; }; ResourceScheduler::ResourceScheduler()
diff --git a/content/browser/media/audible_metrics.cc b/content/browser/media/audible_metrics.cc index 3c17ccc..f07ec2a 100644 --- a/content/browser/media/audible_metrics.cc +++ b/content/browser/media/audible_metrics.cc
@@ -4,6 +4,8 @@ #include "content/browser/media/audible_metrics.h" +#include <utility> + #include "base/metrics/histogram_macros.h" #include "base/metrics/user_metrics.h" #include "base/time/default_tick_clock.h" @@ -37,8 +39,6 @@ } void AudibleMetrics::AddAudibleWebContents(const WebContents* web_contents) { - base::RecordAction(base::UserMetricsAction("Media.Audible.AddTab")); - UMA_HISTOGRAM_CUSTOM_COUNTS( "Media.Audible.ConcurrentTabsWhenStarting", audible_web_contents_.size(), 1, 10, 11); @@ -62,8 +62,6 @@ } void AudibleMetrics::RemoveAudibleWebContents(const WebContents* web_contents) { - base::RecordAction(base::UserMetricsAction("Media.Audible.RemoveTab")); - audible_web_contents_.erase(web_contents); if (audible_web_contents_.size() <= 1 &&
diff --git a/content/browser/media/audible_metrics_unittest.cc b/content/browser/media/audible_metrics_unittest.cc index a337bb1..6989dc7e 100644 --- a/content/browser/media/audible_metrics_unittest.cc +++ b/content/browser/media/audible_metrics_unittest.cc
@@ -26,9 +26,6 @@ static const char* CONCURRENT_TABS_TIME_HISTOGRAM = "Media.Audible.ConcurrentTabsTime"; -static const char* ADD_TAB_USER_ACTION = "Media.Audible.AddTab"; -static const char* REMOVE_TAB_USER_ACTION = "Media.Audible.RemoveTab"; - class AudibleMetricsTest : public testing::Test { public: AudibleMetricsTest() = default; @@ -95,8 +92,6 @@ EXPECT_EQ(0, samples->TotalCount()); } - EXPECT_EQ(0, user_action_tester().GetActionCount(ADD_TAB_USER_ACTION)); - EXPECT_EQ(0, user_action_tester().GetActionCount(REMOVE_TAB_USER_ACTION)); } TEST_F(AudibleMetricsTest, AudibleStart) { @@ -124,8 +119,6 @@ EXPECT_EQ(0, samples->TotalCount()); } - EXPECT_EQ(1, user_action_tester().GetActionCount(ADD_TAB_USER_ACTION)); - EXPECT_EQ(0, user_action_tester().GetActionCount(REMOVE_TAB_USER_ACTION)); } TEST_F(AudibleMetricsTest, AudibleStartAndStop) { @@ -153,9 +146,6 @@ GetHistogramSamplesSinceTestStart(CONCURRENT_TABS_TIME_HISTOGRAM)); EXPECT_EQ(0, samples->TotalCount()); } - - EXPECT_EQ(1, user_action_tester().GetActionCount(ADD_TAB_USER_ACTION)); - EXPECT_EQ(1, user_action_tester().GetActionCount(REMOVE_TAB_USER_ACTION)); } TEST_F(AudibleMetricsTest, AddSameTabIsNoOp) { @@ -186,9 +176,6 @@ GetHistogramSamplesSinceTestStart(CONCURRENT_TABS_TIME_HISTOGRAM)); EXPECT_EQ(0, samples->TotalCount()); } - - EXPECT_EQ(1, user_action_tester().GetActionCount(ADD_TAB_USER_ACTION)); - EXPECT_EQ(0, user_action_tester().GetActionCount(REMOVE_TAB_USER_ACTION)); } TEST_F(AudibleMetricsTest, RemoveUnknownTabIsNoOp) { @@ -201,9 +188,6 @@ MAX_CONCURRENT_TAB_IN_SESSION_HISTOGRAM)->TotalCount()); EXPECT_EQ(0, GetHistogramSamplesSinceTestStart( CONCURRENT_TABS_TIME_HISTOGRAM)->TotalCount()); - - EXPECT_EQ(0, user_action_tester().GetActionCount(ADD_TAB_USER_ACTION)); - EXPECT_EQ(0, user_action_tester().GetActionCount(REMOVE_TAB_USER_ACTION)); } TEST_F(AudibleMetricsTest, ConcurrentTabsInSessionIsIncremental) { @@ -220,9 +204,6 @@ EXPECT_EQ(1, samples->GetCount(2)); EXPECT_EQ(1, samples->GetCount(3)); EXPECT_EQ(1, samples->GetCount(4)); - - EXPECT_EQ(4, user_action_tester().GetActionCount(ADD_TAB_USER_ACTION)); - EXPECT_EQ(0, user_action_tester().GetActionCount(REMOVE_TAB_USER_ACTION)); } TEST_F(AudibleMetricsTest, ConcurrentTabsInSessionKeepTrackOfRemovedTabs) { @@ -240,9 +221,6 @@ EXPECT_EQ(2, samples->TotalCount()); EXPECT_EQ(1, samples->GetCount(1)); EXPECT_EQ(1, samples->GetCount(2)); - - EXPECT_EQ(4, user_action_tester().GetActionCount(ADD_TAB_USER_ACTION)); - EXPECT_EQ(3, user_action_tester().GetActionCount(REMOVE_TAB_USER_ACTION)); } TEST_F(AudibleMetricsTest, ConcurrentTabsInSessionIsNotCountedTwice) { @@ -269,9 +247,6 @@ EXPECT_EQ(1, samples->GetCount(2)); EXPECT_EQ(1, samples->GetCount(3)); EXPECT_EQ(1, samples->GetCount(4)); - - EXPECT_EQ(8, user_action_tester().GetActionCount(ADD_TAB_USER_ACTION)); - EXPECT_EQ(4, user_action_tester().GetActionCount(REMOVE_TAB_USER_ACTION)); } TEST_F(AudibleMetricsTest, ConcurrentTabsWhenStartingAddedPerTab) { @@ -287,9 +262,6 @@ EXPECT_EQ(1, samples->GetCount(1)); } - EXPECT_EQ(2, user_action_tester().GetActionCount(ADD_TAB_USER_ACTION)); - EXPECT_EQ(0, user_action_tester().GetActionCount(REMOVE_TAB_USER_ACTION)); - // Added again: ignored. audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_0, true); audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_1, true); @@ -303,9 +275,6 @@ EXPECT_EQ(1, samples->GetCount(1)); } - EXPECT_EQ(2, user_action_tester().GetActionCount(ADD_TAB_USER_ACTION)); - EXPECT_EQ(0, user_action_tester().GetActionCount(REMOVE_TAB_USER_ACTION)); - // Removing both. audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_0, false); audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_1, false); @@ -319,9 +288,6 @@ EXPECT_EQ(1, samples->GetCount(1)); } - EXPECT_EQ(2, user_action_tester().GetActionCount(ADD_TAB_USER_ACTION)); - EXPECT_EQ(2, user_action_tester().GetActionCount(REMOVE_TAB_USER_ACTION)); - // Adding them after removed, it is counted. audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_0, true); audible_metrics()->UpdateAudibleWebContentsState(WEB_CONTENTS_1, true); @@ -334,9 +300,6 @@ EXPECT_EQ(2, samples->GetCount(0)); EXPECT_EQ(2, samples->GetCount(1)); } - - EXPECT_EQ(4, user_action_tester().GetActionCount(ADD_TAB_USER_ACTION)); - EXPECT_EQ(2, user_action_tester().GetActionCount(REMOVE_TAB_USER_ACTION)); } TEST_F(AudibleMetricsTest, ConcurrentTabsTimeRequiresTwoAudibleTabs) {
diff --git a/content/browser/notifications/notification_database.cc b/content/browser/notifications/notification_database.cc index 19236820..677a327 100644 --- a/content/browser/notifications/notification_database.cc +++ b/content/browser/notifications/notification_database.cc
@@ -328,11 +328,6 @@ continue; } - // Silently ignore the notification if it doesn't have an ID assigned. - // TODO(peter): Remove this clause when Chrome 55 has branched. - if (notification_database_data.notification_id.empty()) - continue; - notification_data_vector->push_back(notification_database_data); }
diff --git a/content/browser/notifications/platform_notification_context_impl.cc b/content/browser/notifications/platform_notification_context_impl.cc index c7a6b2c..b2b372f 100644 --- a/content/browser/notifications/platform_notification_context_impl.cc +++ b/content/browser/notifications/platform_notification_context_impl.cc
@@ -252,10 +252,10 @@ UMA_HISTOGRAM_ENUMERATION("Notifications.Database.ReadForServiceWorkerResult", status, NotificationDatabase::STATUS_COUNT); + std::vector<std::string> obsolete_notifications; + if (status == NotificationDatabase::STATUS_OK) { if (synchronization_supported) { - // Filter out notifications that are not actually on display anymore. - // TODO(miguelg) synchronize the database if there are inconsistencies. for (auto it = notification_datas.begin(); it != notification_datas.end();) { // The database is only used for persistent notifications. @@ -264,6 +264,7 @@ if (displayed_notifications->count(it->notification_id)) { ++it; } else { + obsolete_notifications.push_back(it->notification_id); it = notification_datas.erase(it); } } @@ -272,6 +273,10 @@ BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(callback, true /* success */, notification_datas)); + + // Remove notifications that are not actually on display anymore. + for (const auto& it : obsolete_notifications) + database_->DeleteNotificationData(it, origin); return; }
diff --git a/content/browser/payments/payment_app_browsertest.cc b/content/browser/payments/payment_app_browsertest.cc new file mode 100644 index 0000000..23ddafb --- /dev/null +++ b/content/browser/payments/payment_app_browsertest.cc
@@ -0,0 +1,116 @@ +// 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/command_line.h" +#include "base/macros.h" +#include "base/run_loop.h" +#include "components/payments/payment_app.mojom.h" +#include "content/public/browser/payment_app_provider.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/content_switches.h" +#include "content/public/test/browser_test_utils.h" +#include "content/public/test/content_browser_test.h" +#include "content/public/test/content_browser_test_utils.h" +#include "content/shell/browser/shell.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace content { +namespace { + +void GetAllManifestsCallback(const base::Closure& done_callback, + PaymentAppProvider::Manifests* out_manifests, + PaymentAppProvider::Manifests manifests) { + *out_manifests = std::move(manifests); + done_callback.Run(); +} + +} // namespace + +class PaymentAppBrowserTest : public ContentBrowserTest { + public: + PaymentAppBrowserTest() {} + ~PaymentAppBrowserTest() override {} + + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitch( + switches::kEnableExperimentalWebPlatformFeatures); + } + + void SetUpOnMainThread() override { + https_server_.reset( + new net::EmbeddedTestServer(net::EmbeddedTestServer::TYPE_HTTPS)); + https_server_->ServeFilesFromSourceDirectory("content/test/data"); + ASSERT_TRUE(https_server_->Start()); + ASSERT_TRUE(NavigateToURL( + shell(), + https_server_->GetURL("/payments/payment_app_invocation.html"))); + ContentBrowserTest::SetUpOnMainThread(); + } + + bool RunScript(const std::string& script, std::string* result) { + return content::ExecuteScriptAndExtractString(shell()->web_contents(), + script, result); + } + + std::string PopConsoleString() { + std::string script_result; + EXPECT_TRUE(RunScript("resultQueue.pop()", &script_result)); + return script_result; + } + + void RegisterPaymentApp() { + std::string script_result; + ASSERT_TRUE(RunScript("registerPaymentApp()", &script_result)); + ASSERT_EQ("registered", script_result); + } + + std::vector<int64_t> GetAllPaymentAppIDs() { + base::RunLoop run_loop; + PaymentAppProvider::Manifests manifests; + PaymentAppProvider::GetInstance()->GetAllManifests( + shell()->web_contents()->GetBrowserContext(), + base::Bind(&GetAllManifestsCallback, run_loop.QuitClosure(), + &manifests)); + run_loop.Run(); + + std::vector<int64_t> ids; + for (const auto& manifest : manifests) { + ids.push_back(manifest.first); + } + + return ids; + } + + void InvokePaymentApp(int64_t registration_id) { + payments::mojom::PaymentAppRequestPtr app_request = + payments::mojom::PaymentAppRequest::New(); + app_request->methodData.push_back( + payments::mojom::PaymentMethodData::New()); + app_request->total = payments::mojom::PaymentItem::New(); + app_request->total->amount = payments::mojom::PaymentCurrencyAmount::New(); + PaymentAppProvider::GetInstance()->InvokePaymentApp( + shell()->web_contents()->GetBrowserContext(), registration_id, + std::move(app_request)); + } + + private: + std::unique_ptr<net::EmbeddedTestServer> https_server_; + + DISALLOW_COPY_AND_ASSIGN(PaymentAppBrowserTest); +}; + +IN_PROC_BROWSER_TEST_F(PaymentAppBrowserTest, PaymentAppInvocation) { + RegisterPaymentApp(); + + std::vector<int64_t> ids = GetAllPaymentAppIDs(); + ASSERT_EQ(1U, ids.size()); + + InvokePaymentApp(ids[0]); + + ASSERT_EQ("payment_app_window_ready", PopConsoleString()); + ASSERT_EQ("payment_app_response", PopConsoleString()); +} + +} // namespace content
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc index fd3a626..49abcb2 100644 --- a/content/browser/renderer_host/compositor_impl_android.cc +++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -466,6 +466,7 @@ host_->SetVisible(false); host_->ReleaseCompositorFrameSink(); + has_compositor_frame_sink_ = false; pending_swapbuffers_ = 0; display_.reset(); } else { @@ -532,6 +533,11 @@ void CompositorImpl::DidInitializeCompositorFrameSink() { compositor_frame_sink_request_pending_ = false; + has_compositor_frame_sink_ = true; + for (auto& frame_sink_id : pending_child_frame_sink_ids_) + AddChildFrameSink(frame_sink_id); + + pending_child_frame_sink_ids_.clear(); } void CompositorImpl::DidFailToInitializeCompositorFrameSink() { @@ -706,6 +712,7 @@ void CompositorImpl::DidLoseCompositorFrameSink() { TRACE_EVENT0("compositor", "CompositorImpl::DidLoseCompositorFrameSink"); + has_compositor_frame_sink_ = false; client_->OnSwapBuffersCompleted(0); } @@ -735,6 +742,28 @@ return frame_sink_id_; } +void CompositorImpl::AddChildFrameSink(const cc::FrameSinkId& frame_sink_id) { + if (has_compositor_frame_sink_) { + ui::ContextProviderFactory::GetInstance() + ->GetSurfaceManager() + ->RegisterFrameSinkHierarchy(frame_sink_id_, frame_sink_id); + } else { + pending_child_frame_sink_ids_.insert(frame_sink_id); + } +} + +void CompositorImpl::RemoveChildFrameSink( + const cc::FrameSinkId& frame_sink_id) { + auto it = pending_child_frame_sink_ids_.find(frame_sink_id); + if (it != pending_child_frame_sink_ids_.end()) { + pending_child_frame_sink_ids_.erase(it); + return; + } + ui::ContextProviderFactory::GetInstance() + ->GetSurfaceManager() + ->UnregisterFrameSinkHierarchy(frame_sink_id_, frame_sink_id); +} + bool CompositorImpl::HavePendingReadbacks() { return !readback_layer_tree_->children().empty(); }
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h index 83ff584..6d49a396 100644 --- a/content/browser/renderer_host/compositor_impl_android.h +++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -103,6 +103,8 @@ std::unique_ptr<cc::CopyOutputRequest> request) override; void SetNeedsAnimate() override; cc::FrameSinkId GetFrameSinkId() override; + void AddChildFrameSink(const cc::FrameSinkId& frame_sink_id) override; + void RemoveChildFrameSink(const cc::FrameSinkId& frame_sink_id) override; void SetVisible(bool visible); void CreateLayerTreeHost(); @@ -165,6 +167,9 @@ bool compositor_frame_sink_request_pending_; gpu::Capabilities gpu_capabilities_; + bool has_compositor_frame_sink_ = false; + std::unordered_set<cc::FrameSinkId, cc::FrameSinkIdHash> + pending_child_frame_sink_ids_; base::WeakPtrFactory<CompositorImpl> weak_factory_; DISALLOW_COPY_AND_ASSIGN(CompositorImpl);
diff --git a/content/browser/renderer_host/input/legacy_touch_event_queue.cc b/content/browser/renderer_host/input/legacy_touch_event_queue.cc index 9c3a1e5..c723964 100644 --- a/content/browser/renderer_host/input/legacy_touch_event_queue.cc +++ b/content/browser/renderer_host/input/legacy_touch_event_queue.cc
@@ -28,10 +28,6 @@ // scrolling is active and possible. const double kAsyncTouchMoveIntervalSec = .2; -// A sanity check on touches received to ensure that touch movement outside -// the platform slop region will cause scrolling. -const double kMaxConceivablePlatformSlopRegionLengthDipsSquared = 60. * 60.; - TouchEventWithLatencyInfo ObtainCancelEventForTouchEvent( const TouchEventWithLatencyInfo& event_to_cancel) { TouchEventWithLatencyInfo event = event_to_cancel; @@ -279,59 +275,6 @@ bool sequence_using_mobile_timeout_; }; -// Provides touchmove slop suppression for a touch sequence until a -// (unprevented) touch will trigger immediate scrolling. -class LegacyTouchEventQueue::TouchMoveSlopSuppressor { - public: - TouchMoveSlopSuppressor() : suppressing_touchmoves_(false) {} - - bool FilterEvent(const WebTouchEvent& event) { - if (WebTouchEventTraits::IsTouchSequenceStart(event)) { - suppressing_touchmoves_ = true; - touch_start_location_ = gfx::PointF(event.touches[0].position); - } - - if (event.type() == WebInputEvent::TouchEnd || - event.type() == WebInputEvent::TouchCancel) - suppressing_touchmoves_ = false; - - if (event.type() != WebInputEvent::TouchMove) - return false; - - if (suppressing_touchmoves_) { - if (event.touchesLength > 1) { - suppressing_touchmoves_ = false; - } else if (event.movedBeyondSlopRegion) { - suppressing_touchmoves_ = false; - } else { - // No sane slop region should be larger than 60 DIPs. - DCHECK_LT( - (gfx::PointF(event.touches[0].position) - touch_start_location_) - .LengthSquared(), - kMaxConceivablePlatformSlopRegionLengthDipsSquared); - } - } - - return suppressing_touchmoves_; - } - - void ConfirmTouchEvent(InputEventAckState ack_result) { - if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) - suppressing_touchmoves_ = false; - } - - bool suppressing_touchmoves() const { return suppressing_touchmoves_; } - - private: - bool suppressing_touchmoves_; - - // Sanity check that the upstream touch provider is properly reporting whether - // the touch sequence will cause scrolling. - gfx::PointF touch_start_location_; - - DISALLOW_COPY_AND_ASSIGN(TouchMoveSlopSuppressor); -}; - // This class represents a single coalesced touch event. However, it also keeps // track of all the original touch-events that were coalesced into a single // event. The coalesced event is forwarded to the renderer, while the original @@ -426,7 +369,6 @@ has_handlers_(true), has_handler_for_current_sequence_(false), drop_remaining_touches_in_sequence_(false), - touchmove_slop_suppressor_(new TouchMoveSlopSuppressor), send_touch_events_async_(false), last_sent_touch_timestamp_sec_(0) { if (config.touch_ack_timeout_supported) { @@ -533,8 +475,6 @@ if (timeout_handler_ && timeout_handler_->ConfirmTouchEvent(ack_result)) return; - touchmove_slop_suppressor_->ConfirmTouchEvent(ack_result); - if (touch_queue_.empty()) return; @@ -656,12 +596,6 @@ void LegacyTouchEventQueue::OnGestureScrollEvent( const GestureEventWithLatencyInfo& gesture_event) { if (gesture_event.event.type() == blink::WebInputEvent::GestureScrollBegin) { - if (has_handler_for_current_sequence_ && - !drop_remaining_touches_in_sequence_) { - DCHECK(!touchmove_slop_suppressor_->suppressing_touchmoves()) - << "A touch handler should be offered a touchmove before scrolling."; - } - pending_async_touchmove_.reset(); return; @@ -871,9 +805,6 @@ if (timeout_handler_ && timeout_handler_->FilterEvent(event)) return ACK_WITH_NO_CONSUMER_EXISTS; - if (touchmove_slop_suppressor_->FilterEvent(event)) - return ACK_WITH_NOT_CONSUMED; - if (drop_remaining_touches_in_sequence_ && event.type() != WebInputEvent::TouchCancel) { return ACK_WITH_NO_CONSUMER_EXISTS;
diff --git a/content/browser/renderer_host/input/legacy_touch_event_queue.h b/content/browser/renderer_host/input/legacy_touch_event_queue.h index 16ab57a..60f9c6b7 100644 --- a/content/browser/renderer_host/input/legacy_touch_event_queue.h +++ b/content/browser/renderer_host/input/legacy_touch_event_queue.h
@@ -96,7 +96,6 @@ private: class TouchTimeoutHandler; - class TouchMoveSlopSuppressor; friend class TouchTimeoutHandler; friend class TouchEventQueueTest; @@ -181,10 +180,6 @@ // Optional handler for timed-out touch event acks. std::unique_ptr<TouchTimeoutHandler> timeout_handler_; - // Suppression of TouchMove's within a slop region when a sequence has not yet - // been preventDefaulted. - std::unique_ptr<TouchMoveSlopSuppressor> touchmove_slop_suppressor_; - // Whether touch events should remain buffered and dispatched asynchronously // while a scroll sequence is active. In this mode, touchmove's are throttled // and ack'ed immediately, but remain buffered in |pending_async_touchmove_|
diff --git a/content/browser/renderer_host/input/touch_event_queue_unittest.cc b/content/browser/renderer_host/input/touch_event_queue_unittest.cc index 88b6123..b20f6921 100644 --- a/content/browser/renderer_host/input/touch_event_queue_unittest.cc +++ b/content/browser/renderer_host/input/touch_event_queue_unittest.cc
@@ -1388,9 +1388,9 @@ EXPECT_EQ(0U, GetAndResetAckedEventCount()); } -// Tests that TouchMove's are dropped if within the boundary-inclusive slop -// suppression region for an unconsumed TouchStart. -TEST_F(TouchEventQueueTest, TouchMoveSuppressionIncludingSlopBoundary) { +// Tests that TouchMove's movedBeyondSlopRegion is set to false if within the +// boundary-inclusive slop region for an unconsumed TouchStart. +TEST_F(TouchEventQueueTest, TouchMovedBeyondSlopRegionCheck) { SetUpForTouchMoveSlopTesting(kSlopLengthDips); // Queue a TouchStart. @@ -1399,39 +1399,44 @@ ASSERT_EQ(1U, GetAndResetSentEventCount()); ASSERT_EQ(1U, GetAndResetAckedEventCount()); - // TouchMove's within the region should be suppressed. + // TouchMove's movedBeyondSlopRegion within the slop region is set to false. MoveTouchPoint(0, 0, kHalfSlopLengthDips); - EXPECT_EQ(0U, queued_event_count()); - EXPECT_EQ(0U, GetAndResetSentEventCount()); + EXPECT_EQ(1U, queued_event_count()); + SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(1U, GetAndResetSentEventCount()); EXPECT_EQ(1U, GetAndResetAckedEventCount()); - EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, acked_event_state()); + EXPECT_FALSE(acked_event().movedBeyondSlopRegion); MoveTouchPoint(0, kHalfSlopLengthDips, 0); - EXPECT_EQ(0U, queued_event_count()); - EXPECT_EQ(0U, GetAndResetSentEventCount()); + EXPECT_EQ(1U, queued_event_count()); + SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(1U, GetAndResetSentEventCount()); EXPECT_EQ(1U, GetAndResetAckedEventCount()); - EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, acked_event_state()); + EXPECT_FALSE(acked_event().movedBeyondSlopRegion); MoveTouchPoint(0, -kHalfSlopLengthDips, 0); - EXPECT_EQ(0U, queued_event_count()); - EXPECT_EQ(0U, GetAndResetSentEventCount()); + EXPECT_EQ(1U, queued_event_count()); + SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(1U, GetAndResetSentEventCount()); EXPECT_EQ(1U, GetAndResetAckedEventCount()); - EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, acked_event_state()); + EXPECT_FALSE(acked_event().movedBeyondSlopRegion); MoveTouchPoint(0, -kSlopLengthDips, 0); - EXPECT_EQ(0U, queued_event_count()); - EXPECT_EQ(0U, GetAndResetSentEventCount()); + EXPECT_EQ(1U, queued_event_count()); + SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(1U, GetAndResetSentEventCount()); EXPECT_EQ(1U, GetAndResetAckedEventCount()); - EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, acked_event_state()); + EXPECT_FALSE(acked_event().movedBeyondSlopRegion); MoveTouchPoint(0, 0, kSlopLengthDips); - EXPECT_EQ(0U, queued_event_count()); - EXPECT_EQ(0U, GetAndResetSentEventCount()); + EXPECT_EQ(1U, queued_event_count()); + SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(1U, GetAndResetSentEventCount()); EXPECT_EQ(1U, GetAndResetAckedEventCount()); - EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, acked_event_state()); + EXPECT_FALSE(acked_event().movedBeyondSlopRegion); - // As soon as a TouchMove exceeds the (Euclidean) distance, no more - // TouchMove's should be suppressed. + // When a TouchMove exceeds the (Euclidean) distance, the TouchMove's + // movedBeyondSlopRegion is set to true. const float kFortyFiveDegreeSlopLengthXY = kSlopLengthDips * std::sqrt(2.f) / 2; MoveTouchPoint(0, kFortyFiveDegreeSlopLengthXY + .2f, @@ -1441,113 +1446,26 @@ EXPECT_EQ(0U, GetAndResetAckedEventCount()); SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); EXPECT_EQ(1U, GetAndResetAckedEventCount()); - - // Even TouchMove's within the original slop region should now be forwarded. - MoveTouchPoint(0, 0, 0); - EXPECT_EQ(1U, queued_event_count()); - EXPECT_EQ(1U, GetAndResetSentEventCount()); - EXPECT_EQ(0U, GetAndResetAckedEventCount()); - SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - EXPECT_EQ(1U, GetAndResetAckedEventCount()); - - // A new touch sequence should reset suppression. - ReleaseTouchPoint(0); - PressTouchPoint(0, 0); - SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ASSERT_EQ(2U, GetAndResetSentEventCount()); - ASSERT_EQ(2U, GetAndResetAckedEventCount()); - ASSERT_EQ(0U, queued_event_count()); - - // The slop region is boundary-inclusive. - MoveTouchPoint(0, kSlopLengthDips - 1, 0); - EXPECT_EQ(0U, queued_event_count()); - EXPECT_EQ(0U, GetAndResetSentEventCount()); - EXPECT_EQ(1U, GetAndResetAckedEventCount()); - - MoveTouchPoint(0, kSlopLengthDips, 0); - EXPECT_EQ(0U, queued_event_count()); - EXPECT_EQ(0U, GetAndResetSentEventCount()); - EXPECT_EQ(1U, GetAndResetAckedEventCount()); + EXPECT_TRUE(acked_event().movedBeyondSlopRegion); } -// Tests that TouchMove's are not dropped within the slop suppression region if -// the touchstart was consumed. -TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterTouchConsumed) { - SetUpForTouchMoveSlopTesting(kSlopLengthDips); - - // Queue a TouchStart. - PressTouchPoint(0, 0); - SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED); - ASSERT_EQ(1U, GetAndResetSentEventCount()); - ASSERT_EQ(1U, GetAndResetAckedEventCount()); - - // TouchMove's within the region should not be suppressed, as a touch was - // consumed. - MoveTouchPoint(0, 0, kHalfSlopLengthDips); - EXPECT_EQ(1U, queued_event_count()); - EXPECT_EQ(1U, GetAndResetSentEventCount()); - EXPECT_EQ(0U, GetAndResetAckedEventCount()); -} - -// Tests that even very small TouchMove's are not suppressed when suppression is -// disabled. -TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionIfDisabled) { +// Tests that even very small TouchMove's movedBeyondSlopRegion is set to true +// when the slop region's dimension is 0. +TEST_F(TouchEventQueueTest, MovedBeyondSlopRegionAlwaysTrueIfDimensionZero) { // Queue a TouchStart. PressTouchPoint(0, 0); SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); ASSERT_EQ(1U, GetAndResetSentEventCount()); ASSERT_EQ(1U, GetAndResetAckedEventCount()); - // Small TouchMove's should not be suppressed. + // Small TouchMove's movedBeyondSlopRegion is set to true. MoveTouchPoint(0, 0.001f, 0.001f); EXPECT_EQ(1U, queued_event_count()); EXPECT_EQ(1U, GetAndResetSentEventCount()); EXPECT_EQ(0U, GetAndResetAckedEventCount()); -} - -// Tests that TouchMove's are not dropped if a secondary pointer is present -// during any movement. -TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterMultiTouch) { - SetUpForTouchMoveSlopTesting(kSlopLengthDips); - - // Queue a TouchStart. - PressTouchPoint(0, 0); - SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ASSERT_EQ(1U, GetAndResetSentEventCount()); - ASSERT_EQ(1U, GetAndResetAckedEventCount()); - - // TouchMove's within the region should be suppressed. - MoveTouchPoint(0, 0, kHalfSlopLengthDips); - EXPECT_EQ(0U, queued_event_count()); - EXPECT_EQ(0U, GetAndResetSentEventCount()); - EXPECT_EQ(1U, GetAndResetAckedEventCount()); - - // Simulate a secondary pointer press. - PressTouchPoint(kSlopLengthDips, 0); - SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - EXPECT_EQ(1U, GetAndResetSentEventCount()); - EXPECT_EQ(1U, GetAndResetAckedEventCount()); - - // TouchMove with a secondary pointer should not be suppressed. - MoveTouchPoint(1, kSlopLengthDips+1, 0); - EXPECT_EQ(1U, queued_event_count()); - EXPECT_EQ(1U, GetAndResetSentEventCount()); SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); EXPECT_EQ(1U, GetAndResetAckedEventCount()); - - // Release the secondary pointer. - ReleaseTouchPoint(0); - SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - EXPECT_EQ(1U, GetAndResetSentEventCount()); - EXPECT_EQ(1U, GetAndResetAckedEventCount()); - - // TouchMove's should not should be suppressed, even with the original - // unmoved pointer. - MoveTouchPoint(0, 0, 0); - EXPECT_EQ(1U, queued_event_count()); - EXPECT_EQ(1U, GetAndResetSentEventCount()); - EXPECT_EQ(0U, GetAndResetAckedEventCount()); + EXPECT_TRUE(acked_event().movedBeyondSlopRegion); } // Tests that secondary touch points can be forwarded even if the primary touch
diff --git a/content/browser/renderer_host/input/web_input_event_builders_mac.h b/content/browser/renderer_host/input/web_input_event_builders_mac.h index 21a71bd..d05de51c 100644 --- a/content/browser/renderer_host/input/web_input_event_builders_mac.h +++ b/content/browser/renderer_host/input/web_input_event_builders_mac.h
@@ -23,7 +23,11 @@ class CONTENT_EXPORT WebMouseEventBuilder { public: - static blink::WebMouseEvent Build(NSEvent* event, NSView* view); + static blink::WebMouseEvent Build( + NSEvent* event, + NSView* view, + blink::WebPointerProperties::PointerType pointerType = + blink::WebPointerProperties::PointerType::Mouse); }; class CONTENT_EXPORT WebMouseWheelEventBuilder {
diff --git a/content/browser/renderer_host/input/web_input_event_builders_mac.mm b/content/browser/renderer_host/input/web_input_event_builders_mac.mm index 11f434f7..383e02c5 100644 --- a/content/browser/renderer_host/input/web_input_event_builders_mac.mm +++ b/content/browser/renderer_host/input/web_input_event_builders_mac.mm
@@ -252,7 +252,10 @@ // WebMouseEvent -------------------------------------------------------------- -blink::WebMouseEvent WebMouseEventBuilder::Build(NSEvent* event, NSView* view) { +blink::WebMouseEvent WebMouseEventBuilder::Build( + NSEvent* event, + NSView* view, + blink::WebPointerProperties::PointerType pointerType) { blink::WebInputEvent::Type event_type = blink::WebInputEvent::Type::Undefined; int click_count = 0; blink::WebMouseEvent::Button button = blink::WebMouseEvent::Button::NoButton; @@ -318,11 +321,11 @@ result.button = button; SetWebEventLocationFromEventInView(&result, event, view); - // For NSMouseExited and NSMouseEntered, they do not have a subtype. Styluses - // and mouses share the same cursor, so we will set their pointerType as - // Unknown for now. + // For NSMouseExited and NSMouseEntered events, they do not have a subtype. + // We decide their pointer types by checking if we recevied a + // NSTabletProximity event. if (type == NSMouseExited || type == NSMouseEntered) { - result.pointerType = blink::WebPointerProperties::PointerType::Unknown; + result.pointerType = pointerType; return result; } @@ -352,6 +355,11 @@ if (twist < 0) twist += 360; result.twist = twist; + } else { + event_type = [event isEnteringProximity] + ? blink::WebInputEvent::MouseMove + : blink::WebInputEvent::MouseLeave; + result.setType(event_type); } return result; }
diff --git a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.cc b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.cc index c4a16f2f..c729f6d 100644 --- a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.cc +++ b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.cc
@@ -22,7 +22,8 @@ provider->GetSurfaceManager(), frame_sink_id, nullptr, - nullptr), + true /* handles_frame_sink_id_invalidation */, + true /* needs_sync_points */), client_(std::move(client)), binding_(this, std::move(request)) { binding_.set_connection_error_handler(
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h index 9a167fc..3c9924b 100644 --- a/content/browser/renderer_host/render_view_host_impl.h +++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -32,6 +32,7 @@ #include "third_party/WebKit/public/web/WebConsoleMessage.h" #include "third_party/WebKit/public/web/WebPopupType.h" #include "third_party/skia/include/core/SkColor.h" +#include "ui/base/mojo/window_open_disposition.mojom.h" namespace content {
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index e840fa89..d5f2a617 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -1373,8 +1373,9 @@ operations_allowed, key_modifiers)); } -void RenderWidgetHostImpl::DragTargetDragLeave() { - Send(new DragMsg_TargetDragLeave(GetRoutingID())); +void RenderWidgetHostImpl::DragTargetDragLeave(const gfx::Point& client_point, + const gfx::Point& screen_point) { + Send(new DragMsg_TargetDragLeave(GetRoutingID(), client_point, screen_point)); } void RenderWidgetHostImpl::DragTargetDrop(const DropData& drop_data,
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index cd530d81..1db87d02 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -186,7 +186,8 @@ const gfx::Point& screen_pt, blink::WebDragOperationsMask operations_allowed, int key_modifiers) override; - void DragTargetDragLeave() override; + void DragTargetDragLeave(const gfx::Point& client_point, + const gfx::Point& screen_point) override; // |drop_data| must have been filtered. The embedder should call // FilterDropData before passing the drop data to RWHI. void DragTargetDrop(const DropData& drop_data,
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index 13bc544..02d54e8 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -482,8 +482,6 @@ bool handled = true; IPC_BEGIN_MESSAGE_MAP(RenderWidgetHostViewAndroid, message) IPC_MESSAGE_HANDLER(ViewHostMsg_StartContentIntent, OnStartContentIntent) - IPC_MESSAGE_HANDLER(ViewHostMsg_SmartClipDataExtracted, - OnSmartClipDataExtracted) IPC_MESSAGE_HANDLER(ViewHostMsg_ShowUnhandledTapUIIfNeeded, OnShowUnhandledTapUIIfNeeded) IPC_MESSAGE_UNHANDLED(handled = false) @@ -811,14 +809,6 @@ content_view_core_->StartContentIntent(content_url, is_main_frame); } -void RenderWidgetHostViewAndroid::OnSmartClipDataExtracted( - const base::string16& text, - const base::string16& html, - const gfx::Rect rect) { - if (content_view_core_) - content_view_core_->OnSmartClipDataExtracted(text, html, rect); -} - bool RenderWidgetHostViewAndroid::OnTouchEvent( const ui::MotionEvent& event) { if (!host_) @@ -1413,8 +1403,7 @@ ui::WindowAndroidCompositor* compositor = view_.GetWindowAndroid()->GetCompositor(); if (compositor) { - delegated_frame_host_->RegisterFrameSinkHierarchy( - compositor->GetFrameSinkId()); + delegated_frame_host_->AttachToCompositor(compositor); } } @@ -1439,7 +1428,7 @@ // If the DFH has already been destroyed, it will have cleaned itself up. // This happens in some WebView cases. if (delegated_frame_host_) - delegated_frame_host_->UnregisterFrameSinkHierarchy(); + delegated_frame_host_->DetachFromCompositor(); DCHECK(!begin_frame_source_); } @@ -1824,8 +1813,7 @@ if (observing_root_window_) { ui::WindowAndroidCompositor* compositor = view_.GetWindowAndroid()->GetCompositor(); - delegated_frame_host_->RegisterFrameSinkHierarchy( - compositor->GetFrameSinkId()); + delegated_frame_host_->AttachToCompositor(compositor); } } @@ -1834,7 +1822,7 @@ DCHECK(using_browser_compositor_); RunAckCallbacks(); overscroll_controller_.reset(); - delegated_frame_host_->UnregisterFrameSinkHierarchy(); + delegated_frame_host_->DetachFromCompositor(); } void RenderWidgetHostViewAndroid::OnBeginFrame(const cc::BeginFrameArgs& args) {
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h index 265dac3..a52a7a11 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.h +++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -203,9 +203,6 @@ void SendGestureEvent(const blink::WebGestureEvent& event); void OnStartContentIntent(const GURL& content_url, bool is_main_frame); - void OnSmartClipDataExtracted(const base::string16& text, - const base::string16& html, - const gfx::Rect rect); bool OnTouchEvent(const ui::MotionEvent& event); bool OnTouchHandleEvent(const ui::MotionEvent& event);
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h index 6c1efb1d..aafd66ca 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.h +++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -170,6 +170,11 @@ // key down event. BOOL suppressNextEscapeKeyUp_; + // This is used to indicate if a stylus is currently in the proximity of the + // tablet. + bool isStylusEnteringProximity_; + blink::WebPointerProperties::PointerType pointerType_; + // The set of key codes from key down events that we haven't seen the matching // key up events yet. // Used for filtering out non-matching NSKeyUp events.
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm index 98d34453..936a12b8 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -1731,6 +1731,7 @@ canBeKeyView_ = YES; opaque_ = YES; pinchHasReachedZoomThreshold_ = false; + isStylusEnteringProximity_ = false; // OpenGL support: if ([self respondsToSelector: @@ -1878,10 +1879,20 @@ return; } + // Set the pointer type when we are receiving a NSMouseEntered event and the + // following NSMouseExited event should have the same pointer type. + NSEventType type = [theEvent type]; + if (type == NSMouseEntered) { + pointerType_ = isStylusEnteringProximity_ + ? blink::WebPointerProperties::PointerType::Pen + : blink::WebPointerProperties::PointerType::Mouse; + } + if ([self shouldIgnoreMouseEvent:theEvent]) { // If this is the first such event, send a mouse exit to the host view. if (!mouseEventWasIgnored_ && renderWidgetHostView_->render_widget_host_) { - WebMouseEvent exitEvent = WebMouseEventBuilder::Build(theEvent, self); + WebMouseEvent exitEvent = + WebMouseEventBuilder::Build(theEvent, self, pointerType_); exitEvent.setType(WebInputEvent::MouseLeave); exitEvent.button = WebMouseEvent::Button::NoButton; renderWidgetHostView_->ForwardMouseEvent(exitEvent); @@ -1894,7 +1905,8 @@ // If this is the first mouse event after a previous event that was ignored // due to the hitTest, send a mouse enter event to the host view. if (renderWidgetHostView_->render_widget_host_) { - WebMouseEvent enterEvent = WebMouseEventBuilder::Build(theEvent, self); + WebMouseEvent enterEvent = + WebMouseEventBuilder::Build(theEvent, self, pointerType_); enterEvent.setType(WebInputEvent::MouseMove); enterEvent.button = WebMouseEvent::Button::NoButton; ui::LatencyInfo latency_info(ui::SourceEventType::OTHER); @@ -1916,8 +1928,6 @@ // popup. A click outside the text field would cause the text field to drop // the focus, and then EditorClientImpl::textFieldDidEndEditing() would cancel // the popup anyway, so we're OK. - - NSEventType type = [theEvent type]; if (type == NSLeftMouseDown) hasOpenMouseDown_ = YES; else if (type == NSLeftMouseUp) @@ -1934,7 +1944,8 @@ [self finishComposingText]; } - WebMouseEvent event = WebMouseEventBuilder::Build(theEvent, self); + WebMouseEvent event = + WebMouseEventBuilder::Build(theEvent, self, pointerType_); ui::LatencyInfo latency_info(ui::SourceEventType::OTHER); latency_info.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0); if (renderWidgetHostView_->ShouldRouteEvent(event)) { @@ -1946,6 +1957,11 @@ } } +- (void)tabletEvent:(NSEvent*)theEvent { + if ([theEvent type] == NSTabletProximity) + isStylusEnteringProximity_ = [theEvent isEnteringProximity]; +} + - (BOOL)performKeyEquivalent:(NSEvent*)theEvent { // |performKeyEquivalent:| is sent to all views of a window, not only down the // responder chain (cf. "Handling Key Equivalents" in @@ -2351,8 +2367,11 @@ return; } dispatch_async(dispatch_get_main_queue(), ^{ + NSPoint flippedBaselinePoint = { + baselinePoint.x, [view frame].size.height - baselinePoint.y, + }; [view showDefinitionForAttributedString:string - atPoint:baselinePoint]; + atPoint:flippedBaselinePoint]; }); }
diff --git a/content/browser/screen_orientation/screen_orientation.cc b/content/browser/screen_orientation/screen_orientation.cc deleted file mode 100644 index 6296fbc..0000000 --- a/content/browser/screen_orientation/screen_orientation.cc +++ /dev/null
@@ -1,46 +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. - -#include "content/browser/screen_orientation/screen_orientation.h" - -#include "content/public/browser/navigation_handle.h" -#include "content/public/browser/screen_orientation_provider.h" -#include "content/public/browser/web_contents.h" - -namespace content { - -ScreenOrientation::ScreenOrientation(WebContents* web_contents) - : WebContentsObserver(web_contents), - bindings_(web_contents, this), - weak_factory_(this) { - provider_.reset(new ScreenOrientationProvider(web_contents)); -} - -ScreenOrientation::~ScreenOrientation() = default; - -void ScreenOrientation::LockOrientation( - blink::WebScreenOrientationLockType orientation, - const LockOrientationCallback& callback) { - provider_->LockOrientation(orientation, callback); -} - -void ScreenOrientation::UnlockOrientation() { - provider_->UnlockOrientation(); -} - -void ScreenOrientation::DidFinishNavigation( - NavigationHandle* navigation_handle) { - if (!navigation_handle->IsInMainFrame() || - !navigation_handle->HasCommitted() || - navigation_handle->IsSamePage()) { - return; - } - provider_->UnlockOrientation(); -} - -ScreenOrientationProvider* ScreenOrientation::GetScreenOrientationProvider() { - return provider_.get(); -} - -} // namespace content
diff --git a/content/browser/screen_orientation/screen_orientation.h b/content/browser/screen_orientation/screen_orientation.h deleted file mode 100644 index af3d84e..0000000 --- a/content/browser/screen_orientation/screen_orientation.h +++ /dev/null
@@ -1,42 +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 CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_H -#define CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_H - -#include "base/memory/weak_ptr.h" -#include "content/public/browser/web_contents_binding_set.h" -#include "content/public/browser/web_contents_observer.h" -#include "device/screen_orientation/public/interfaces/screen_orientation.mojom.h" - -namespace content { - -class ScreenOrientationProvider; -class WebContents; - -class ScreenOrientation : public device::mojom::ScreenOrientation, - public WebContentsObserver { - public: - explicit ScreenOrientation(WebContents* web_contents); - ~ScreenOrientation() override; - - ScreenOrientationProvider* GetScreenOrientationProvider(); - - private: - // ScreenOrientation: - void LockOrientation(blink::WebScreenOrientationLockType orientation, - const LockOrientationCallback& callback) override; - void UnlockOrientation() override; - - // WebContentsObserver: - void DidFinishNavigation(NavigationHandle* navigation_handle) override; - - std::unique_ptr<ScreenOrientationProvider> provider_; - WebContentsFrameBindingSet<device::mojom::ScreenOrientation> bindings_; - base::WeakPtrFactory<ScreenOrientation> weak_factory_; -}; - -} // namespace content - -#endif // CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_H
diff --git a/content/browser/screen_orientation/screen_orientation_provider_unittest.cc b/content/browser/screen_orientation/screen_orientation_provider_unittest.cc new file mode 100644 index 0000000..ba44f6f0 --- /dev/null +++ b/content/browser/screen_orientation/screen_orientation_provider_unittest.cc
@@ -0,0 +1,343 @@ +// 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 "content/public/browser/screen_orientation_provider.h" + +#include "base/optional.h" +#include "base/run_loop.h" +#include "content/common/frame_messages.h" +#include "content/public/browser/screen_orientation_delegate.h" +#include "content/public/browser/web_contents_delegate.h" +#include "content/test/test_render_view_host.h" +#include "content/test/test_web_contents.h" +#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h" + +namespace content { + +using device::mojom::ScreenOrientationLockResult; + +namespace { + +class FakeScreenOrientationDelegate : public ScreenOrientationDelegate { + public: + FakeScreenOrientationDelegate(bool supported, bool full_screen_required) + : supported_(supported), full_screen_required_(full_screen_required) { + ScreenOrientationProvider::SetDelegate(this); + } + + ~FakeScreenOrientationDelegate() override = default; + + bool FullScreenRequired(WebContents* web_contents) override { + return full_screen_required_; + } + + bool ScreenOrientationProviderSupported() override { return supported_; } + + void Lock(WebContents* web_contents, + blink::WebScreenOrientationLockType lock_orientation) override { + lock_count_++; + } + + void Unlock(WebContents* web_contents) override { unlock_count_++; } + + int lock_count() const { return lock_count_; } + int unlock_count() const { return unlock_count_; } + + private: + bool supported_ = true; + bool full_screen_required_ = false; + + int lock_count_ = 0; + int unlock_count_ = 0; + + DISALLOW_COPY_AND_ASSIGN(FakeScreenOrientationDelegate); +}; + +class FakeWebContentsDelegate : public WebContentsDelegate { + public: + FakeWebContentsDelegate() = default; + ~FakeWebContentsDelegate() override = default; + + void EnterFullscreenModeForTab(WebContents* web_contents, + const GURL& origin) override { + fullscreened_contents_ = web_contents; + } + + void ExitFullscreenModeForTab(WebContents* web_contents) override { + fullscreened_contents_ = nullptr; + } + + bool IsFullscreenForTabOrPending( + const WebContents* web_contents) const override { + return fullscreened_contents_ && web_contents == fullscreened_contents_; + } + + private: + WebContents* fullscreened_contents_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(FakeWebContentsDelegate); +}; + +void LockResultCallback(base::Optional<ScreenOrientationLockResult>* out_result, + ScreenOrientationLockResult result) { + *out_result = result; +} + +} // namespace + +class ScreenOrientationProviderTest : public RenderViewHostImplTestHarness { + public: + ScreenOrientationProviderTest() = default; + + void SetUp() override { + content::RenderViewHostImplTestHarness::SetUp(); + + contents()->SetDelegate(&wc_delegate_); + } + + // Helpers for testing ScreenOrientationProvider methods. + void CallLockAndGetResult( + blink::WebScreenOrientationLockType orientation, + base::Optional<ScreenOrientationLockResult>* out_result) { + contents()->GetScreenOrientationProvider()->LockOrientation( + orientation, base::Bind(&LockResultCallback, out_result)); + + base::RunLoop().RunUntilIdle(); + } + + void CallUnlock() { + contents()->GetScreenOrientationProvider()->UnlockOrientation(); + } + + private: + FakeWebContentsDelegate wc_delegate_; +}; + +// Lock operation is not available. +TEST_F(ScreenOrientationProviderTest, DelegateNotAvailableLockOnce) { + // No ScreenOrientationDelegate. + base::Optional<ScreenOrientationLockResult> result_1; + CallLockAndGetResult(blink::WebScreenOrientationLockType:: + WebScreenOrientationLockLandscapeSecondary, + &result_1); + EXPECT_EQ(ScreenOrientationLockResult:: + SCREEN_ORIENTATION_LOCK_RESULT_ERROR_NOT_AVAILABLE, + *result_1); + + // ScreenOrientationDelegate not supported. + FakeScreenOrientationDelegate delegate(false, false); + base::Optional<ScreenOrientationLockResult> result_2; + CallLockAndGetResult(blink::WebScreenOrientationLockType:: + WebScreenOrientationLockLandscapeSecondary, + &result_2); + EXPECT_EQ(ScreenOrientationLockResult:: + SCREEN_ORIENTATION_LOCK_RESULT_ERROR_NOT_AVAILABLE, + *result_2); +} + +// Full screen is not required by delegate, normally lock once. +TEST_F(ScreenOrientationProviderTest, DelegateLockOnce) { + // ScreenOrientationDelegate does not require full screen. + FakeScreenOrientationDelegate delegate(true, false); + + // Navigate to a site. + const GURL url("http://www.google.com"); + controller().LoadURL(url, Referrer(), ui::PAGE_TRANSITION_TYPED, + std::string()); + + base::Optional<ScreenOrientationLockResult> result_1; + CallLockAndGetResult(blink::WebScreenOrientationLockType:: + WebScreenOrientationLockLandscapeSecondary, + &result_1); + // Lock request is pending. + EXPECT_FALSE(result_1.has_value()); + // Delegate did apply lock once. + EXPECT_EQ(1, delegate.lock_count()); +} + +// Full screen is required by delegate. +TEST_F(ScreenOrientationProviderTest, DelegateRequireFullScreenLockOnce) { + // ScreenOrientationDelegate requires full screen. + FakeScreenOrientationDelegate delegate(true, true); + + // Navigate to a site. + const GURL url("http://www.google.com"); + controller().LoadURL(url, Referrer(), ui::PAGE_TRANSITION_TYPED, + std::string()); + + // Current web contents is not in full screen. + ASSERT_FALSE(contents()->IsFullscreenForCurrentTab()); + base::Optional<ScreenOrientationLockResult> result_1; + CallLockAndGetResult(blink::WebScreenOrientationLockType:: + WebScreenOrientationLockLandscapeSecondary, + &result_1); + EXPECT_EQ(ScreenOrientationLockResult:: + SCREEN_ORIENTATION_LOCK_RESULT_ERROR_FULLSCREEN_REQUIRED, + *result_1); + // Delegate did not apply any lock. + EXPECT_EQ(0, delegate.lock_count()); + + // Simulates entering full screen. + main_test_rfh()->OnMessageReceived( + FrameHostMsg_ToggleFullscreen(main_test_rfh()->GetRoutingID(), true)); + ASSERT_TRUE(contents()->IsFullscreenForCurrentTab()); + + base::Optional<ScreenOrientationLockResult> result_2; + CallLockAndGetResult(blink::WebScreenOrientationLockType:: + WebScreenOrientationLockLandscapeSecondary, + &result_2); + // Lock request is pending. + EXPECT_FALSE(result_2.has_value()); + // Delegate did apply lock once. + EXPECT_EQ(1, delegate.lock_count()); +} + +// Lock once, then unlock once, the pending lock request will be cancelled. +TEST_F(ScreenOrientationProviderTest, DelegateLockThenUnlock) { + FakeScreenOrientationDelegate delegate(true, false); + + // Navigate to a site. + const GURL url("http://www.google.com"); + controller().LoadURL(url, Referrer(), ui::PAGE_TRANSITION_TYPED, + std::string()); + + base::Optional<ScreenOrientationLockResult> result_1; + CallLockAndGetResult(blink::WebScreenOrientationLockType:: + WebScreenOrientationLockLandscapeSecondary, + &result_1); + // The lock request will be pending. + EXPECT_FALSE(result_1.has_value()); + // Delegate did apply lock once. + EXPECT_EQ(1, delegate.lock_count()); + EXPECT_EQ(0, delegate.unlock_count()); + + CallUnlock(); + // The pending lock request is cancelled. + EXPECT_EQ(ScreenOrientationLockResult:: + SCREEN_ORIENTATION_LOCK_RESULT_ERROR_CANCELED, + result_1); + // Delegate did apply unlock once. + EXPECT_EQ(1, delegate.unlock_count()); +} + +// Lock twice, the first lock request will be cancelled by the second one. +TEST_F(ScreenOrientationProviderTest, DelegateLockThenLock) { + FakeScreenOrientationDelegate delegate(true, false); + + // Navigate to a site. + const GURL url("http://www.google.com"); + controller().LoadURL(url, Referrer(), ui::PAGE_TRANSITION_TYPED, + std::string()); + + base::Optional<ScreenOrientationLockResult> result_1; + CallLockAndGetResult(blink::WebScreenOrientationLockType:: + WebScreenOrientationLockLandscapeSecondary, + &result_1); + // The lock request will be pending. + EXPECT_FALSE(result_1.has_value()); + // Delegate did apply lock once. + EXPECT_EQ(1, delegate.lock_count()); + EXPECT_EQ(0, delegate.unlock_count()); + + base::Optional<ScreenOrientationLockResult> result_2; + CallLockAndGetResult(blink::WebScreenOrientationLockType:: + WebScreenOrientationLockLandscapeSecondary, + &result_2); + // The pending lock request is cancelled. + EXPECT_EQ(ScreenOrientationLockResult:: + SCREEN_ORIENTATION_LOCK_RESULT_ERROR_CANCELED, + result_1); + // The second one became pending. + EXPECT_FALSE(result_2.has_value()); + // Delegate did apply lock once more. + EXPECT_EQ(2, delegate.lock_count()); + EXPECT_EQ(0, delegate.unlock_count()); +} + +// Unlock won't be applied if no lock has been applied previously. +TEST_F(ScreenOrientationProviderTest, NoUnlockWithoutLock) { + FakeScreenOrientationDelegate delegate(true, false); + + // Navigate to a site. + const GURL url("http://www.google.com"); + controller().LoadURL(url, Referrer(), ui::PAGE_TRANSITION_TYPED, + std::string()); + + CallUnlock(); + // Delegate did not apply any unlock. + EXPECT_EQ(0, delegate.unlock_count()); +} + +// If lock already applied once in full screen, then unlock should be triggered +// once automatically when exiting full screen, and previous pending lock +// request will be cancelled. +TEST_F(ScreenOrientationProviderTest, UnlockWhenExitingFullScreen) { + // ScreenOrientationDelegate requires full screen. + FakeScreenOrientationDelegate delegate(true, true); + + // Navigate to a site. + const GURL url("http://www.google.com"); + controller().LoadURL(url, Referrer(), ui::PAGE_TRANSITION_TYPED, + std::string()); + + // Simulates entering full screen. + main_test_rfh()->OnMessageReceived( + FrameHostMsg_ToggleFullscreen(main_test_rfh()->GetRoutingID(), true)); + ASSERT_TRUE(contents()->IsFullscreenForCurrentTab()); + + base::Optional<ScreenOrientationLockResult> result; + CallLockAndGetResult(blink::WebScreenOrientationLockType:: + WebScreenOrientationLockLandscapeSecondary, + &result); + // The lock request will be pending. + EXPECT_FALSE(result.has_value()); + // Delegate did apply lock once. + EXPECT_EQ(1, delegate.lock_count()); + EXPECT_EQ(0, delegate.unlock_count()); + + // Simulates exiting full screen. + main_test_rfh()->OnMessageReceived( + FrameHostMsg_ToggleFullscreen(main_test_rfh()->GetRoutingID(), false)); + ASSERT_FALSE(contents()->IsFullscreenForCurrentTab()); + // The pending lock request is cancelled. + EXPECT_EQ(ScreenOrientationLockResult:: + SCREEN_ORIENTATION_LOCK_RESULT_ERROR_CANCELED, + result); + // Delegate did apply unlock once. + EXPECT_EQ(1, delegate.unlock_count()); +} + +// If lock already applied once, then unlock should be triggered once +// automatically when navigating to other web page, and previous pending lock +// request will be cancelled. +TEST_F(ScreenOrientationProviderTest, UnlockWhenNavigation) { + FakeScreenOrientationDelegate delegate(true, false); + + // Navigate to a site. + const GURL url("http://www.google.com"); + controller().LoadURL(url, Referrer(), ui::PAGE_TRANSITION_TYPED, + std::string()); + + base::Optional<ScreenOrientationLockResult> result; + CallLockAndGetResult(blink::WebScreenOrientationLockType:: + WebScreenOrientationLockLandscapeSecondary, + &result); + // The lock request will be pending. + EXPECT_FALSE(result.has_value()); + // Delegate did apply lock once. + EXPECT_EQ(1, delegate.lock_count()); + EXPECT_EQ(0, delegate.unlock_count()); + + // Navigate to another site. + const GURL another_url("http://www.google.com/abc.html"); + contents()->NavigateAndCommit(another_url); + // The pending lock request is cancelled. + EXPECT_EQ(ScreenOrientationLockResult:: + SCREEN_ORIENTATION_LOCK_RESULT_ERROR_CANCELED, + result); + // Delegate did apply unlock once. + EXPECT_EQ(1, delegate.unlock_count()); +} + +} // namespace content
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc index 61900c1..0fe04b4 100644 --- a/content/browser/service_worker/service_worker_browsertest.cc +++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -2581,6 +2581,7 @@ int size_result) { ASSERT_EQ(net::OK, size_result); if (!blob_reader_->has_side_data()) { + blob_reader_ = nullptr; continuation.Run(); return; } @@ -2599,6 +2600,7 @@ storage::BlobReader::Status status) { ASSERT_NE(storage::BlobReader::Status::NET_ERROR, status); *result = blob_reader_->side_data()->size(); + blob_reader_ = nullptr; continuation.Run(); }
diff --git a/content/browser/site_per_process_mac_browsertest.mm b/content/browser/site_per_process_mac_browsertest.mm index 01b79731..43e5f344 100644 --- a/content/browser/site_per_process_mac_browsertest.mm +++ b/content/browser/site_per_process_mac_browsertest.mm
@@ -89,9 +89,6 @@ std::string word = helper.word(); // Now get it at a given point. - point.SetPoint(point.x(), - child_widget_host->GetView()->GetViewBounds().size().height() - - point.y()); helper.WaitForStringAtPoint(child_widget_host, point); EXPECT_EQ(word, helper.word()); EXPECT_EQ("This", word); @@ -116,9 +113,6 @@ std::string word = helper.word(); // Now get it at a given point. - point.SetPoint( - point.x(), - widget_host->GetView()->GetViewBounds().size().height() - point.y()); helper.WaitForStringAtPoint(widget_host, point); EXPECT_EQ(word, helper.word()); EXPECT_EQ("This", word);
diff --git a/content/browser/web_contents/web_contents_android.cc b/content/browser/web_contents/web_contents_android.cc index 412213d..c373a20 100644 --- a/content/browser/web_contents/web_contents_android.cc +++ b/content/browser/web_contents/web_contents_android.cc
@@ -72,6 +72,15 @@ Java_WebContentsImpl_onEvaluateJavaScriptResult(env, j_json, callback); } +void SmartClipCallback(const ScopedJavaGlobalRef<jobject>& callback, + const base::string16& text, + const base::string16& html) { + JNIEnv* env = base::android::AttachCurrentThread(); + ScopedJavaLocalRef<jstring> jtext = ConvertUTF16ToJavaString(env, text); + ScopedJavaLocalRef<jstring> jhtml = ConvertUTF16ToJavaString(env, html); + Java_WebContentsImpl_onSmartClipDataExtracted(env, jtext, jhtml, callback); +} + struct AccessibilitySnapshotParams { AccessibilitySnapshotParams() : has_tree_data(false), should_select_leaf_nodes(false) {} @@ -597,6 +606,26 @@ return web_contents_->GetThemeColor(); } +void WebContentsAndroid::RequestSmartClipExtract( + JNIEnv* env, + const JavaParamRef<jobject>& obj, + const JavaParamRef<jobject>& callback, + jint x, + jint y, + jint width, + jint height) { + // Secure the Java callback in a scoped object and give ownership of it to the + // base::Callback. + ScopedJavaGlobalRef<jobject> j_callback; + j_callback.Reset(env, callback); + + RenderFrameHostImpl::SmartClipCallback smart_clip_callback = + base::Bind(&SmartClipCallback, j_callback); + + web_contents_->GetMainFrame()->RequestSmartClipExtract( + smart_clip_callback, gfx::Rect(x, y, width, height)); +} + void WebContentsAndroid::RequestAccessibilitySnapshot( JNIEnv* env, const JavaParamRef<jobject>& obj,
diff --git a/content/browser/web_contents/web_contents_android.h b/content/browser/web_contents/web_contents_android.h index ab17833..1cafa20 100644 --- a/content/browser/web_contents/web_contents_android.h +++ b/content/browser/web_contents/web_contents_android.h
@@ -152,6 +152,15 @@ jint GetThemeColor(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj); + void RequestSmartClipExtract( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + const base::android::JavaParamRef<jobject>& callback, + jint x, + jint y, + jint width, + jint height); + void RequestAccessibilitySnapshot( JNIEnv* env, const base::android::JavaParamRef<jobject>& obj,
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 513a29b..01a81011 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -74,7 +74,6 @@ #include "content/browser/renderer_host/render_widget_host_input_event_router.h" #include "content/browser/renderer_host/render_widget_host_view_base.h" #include "content/browser/renderer_host/text_input_manager.h" -#include "content/browser/screen_orientation/screen_orientation.h" #include "content/browser/site_instance_impl.h" #include "content/browser/web_contents/web_contents_view_child_frame.h" #include "content/browser/web_contents/web_contents_view_guest.h" @@ -930,6 +929,11 @@ return view_.get(); } +ScreenOrientationProvider* WebContentsImpl::GetScreenOrientationProvider() + const { + return screen_orientation_provider_.get(); +} + SkColor WebContentsImpl::GetThemeColor() const { return theme_color_; } @@ -1589,7 +1593,7 @@ NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED, NotificationService::AllBrowserContextsAndSources()); - screen_orientation_.reset(new ScreenOrientation(this)); + screen_orientation_provider_.reset(new ScreenOrientationProvider(this)); manifest_manager_host_.reset(new ManifestManagerHost(this)); @@ -2438,10 +2442,6 @@ return wake_lock_service_context_.get(); } -ScreenOrientationProvider* WebContentsImpl::GetScreenOrientationProvider() { - return screen_orientation_.get()->GetScreenOrientationProvider(); -} - void WebContentsImpl::OnShowValidationMessage( RenderViewHostImpl* source, const gfx::Rect& anchor_in_root_view,
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index bbbe490..4ece254c 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -72,7 +72,6 @@ class RenderWidgetHostImpl; class RenderWidgetHostInputEventRouter; class SavePackage; -class ScreenOrientation; class ScreenOrientationProvider; class SiteInstance; class TestWebContents; @@ -210,6 +209,8 @@ WebContentsView* GetView() const; + ScreenOrientationProvider* GetScreenOrientationProvider() const; + bool should_normally_be_visible() { return should_normally_be_visible_; } // Indicate if the window has been occluded, and pass this to the views, only @@ -478,7 +479,6 @@ int browser_plugin_instance_id) override; device::GeolocationServiceContext* GetGeolocationServiceContext() override; device::WakeLockServiceContext* GetWakeLockServiceContext() override; - ScreenOrientationProvider* GetScreenOrientationProvider() override; void EnterFullscreenMode(const GURL& origin) override; void ExitFullscreenMode(bool will_cause_resize) override; bool ShouldRouteMessageEvent( @@ -1438,7 +1438,7 @@ std::unique_ptr<device::WakeLockServiceContext> wake_lock_service_context_; - std::unique_ptr<ScreenOrientation> screen_orientation_; + std::unique_ptr<ScreenOrientationProvider> screen_orientation_provider_; std::unique_ptr<ManifestManagerHost> manifest_manager_host_;
diff --git a/content/browser/web_contents/web_contents_view_android.cc b/content/browser/web_contents/web_contents_view_android.cc index 21b2fbc..eed15aa 100644 --- a/content/browser/web_contents/web_contents_view_android.cc +++ b/content/browser/web_contents/web_contents_view_android.cc
@@ -365,7 +365,8 @@ } void WebContentsViewAndroid::OnDragExited() { - web_contents_->GetRenderViewHost()->GetWidget()->DragTargetDragLeave(); + web_contents_->GetRenderViewHost()->GetWidget()->DragTargetDragLeave( + gfx::Point(), gfx::Point()); } void WebContentsViewAndroid::OnPerformDrop(DropData* drop_data,
diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc index ab629389..1273c58 100644 --- a/content/browser/web_contents/web_contents_view_aura.cc +++ b/content/browser/web_contents/web_contents_view_aura.cc
@@ -156,17 +156,10 @@ // necessary. void PrepareDragForFileContents(const DropData& drop_data, ui::OSExchangeData::Provider* provider) { - base::FilePath file_name = - base::FilePath::FromUTF16Unsafe(drop_data.file_description_filename); - // Images without ALT text will only have a file extension so we need to - // synthesize one from the provided extension and URL. - if (file_name.BaseName().RemoveExtension().empty()) { - const base::FilePath::StringType extension = file_name.Extension(); - // Retrieve the name from the URL. - file_name = net::GenerateFileName(drop_data.url, "", "", "", "", "") - .ReplaceExtension(extension); - } - provider->SetFileContents(file_name, drop_data.file_contents); + base::Optional<base::FilePath> filename = + drop_data.GetSafeFilenameForImageFileContents(); + if (filename) + provider->SetFileContents(*filename, drop_data.file_contents); } #endif @@ -582,10 +575,28 @@ if (screen_position_client) screen_position_client->ConvertPointFromScreen(window, &client_loc); - // TODO(paulmeyer): In the OOPIF case, should |client_loc| be converted to the - // coordinates local to |source_rwh|? See crbug.com/647249. - web_contents_->DragSourceEndedAt(client_loc.x(), client_loc.y(), - screen_loc.x(), screen_loc.y(), ops, + // |client_loc| and |screen_loc| are in the root coordinate space, for + // non-root RenderWidgetHosts they need to be transformed. + gfx::Point transformed_point = client_loc; + gfx::Point transformed_screen_point = screen_loc; + if (source_rwh && web_contents_->GetRenderWidgetHostView()) { + static_cast<RenderWidgetHostViewBase*>( + web_contents_->GetRenderWidgetHostView()) + ->TransformPointToCoordSpaceForView( + client_loc, + static_cast<RenderWidgetHostViewBase*>(source_rwh->GetView()), + &transformed_point); + static_cast<RenderWidgetHostViewBase*>( + web_contents_->GetRenderWidgetHostView()) + ->TransformPointToCoordSpaceForView( + screen_loc, + static_cast<RenderWidgetHostViewBase*>(source_rwh->GetView()), + &transformed_screen_point); + } + + web_contents_->DragSourceEndedAt(transformed_point.x(), transformed_point.y(), + transformed_screen_point.x(), + transformed_screen_point.y(), ops, source_rwh); web_contents_->SystemDragEnded(source_rwh); @@ -1208,9 +1219,26 @@ if (!IsValidDragTarget(target_rwh)) return ui::DragDropTypes::DRAG_NONE; + gfx::Point screen_pt = event.root_location(); if (target_rwh != current_rwh_for_drag_.get()) { - if (current_rwh_for_drag_) - current_rwh_for_drag_->DragTargetDragLeave(); + if (current_rwh_for_drag_) { + gfx::Point transformed_leave_point = event.location(); + gfx::Point transformed_screen_point = screen_pt; + static_cast<RenderWidgetHostViewBase*>( + web_contents_->GetRenderWidgetHostView()) + ->TransformPointToCoordSpaceForView( + event.location(), static_cast<RenderWidgetHostViewBase*>( + current_rwh_for_drag_->GetView()), + &transformed_leave_point); + static_cast<RenderWidgetHostViewBase*>( + web_contents_->GetRenderWidgetHostView()) + ->TransformPointToCoordSpaceForView( + screen_pt, static_cast<RenderWidgetHostViewBase*>( + current_rwh_for_drag_->GetView()), + &transformed_screen_point); + current_rwh_for_drag_->DragTargetDragLeave(transformed_leave_point, + transformed_screen_point); + } OnDragEntered(event); } @@ -1218,7 +1246,6 @@ return ui::DragDropTypes::DRAG_NONE; blink::WebDragOperationsMask op = ConvertToWeb(event.source_operations()); - gfx::Point screen_pt = event.root_location(); target_rwh->DragTargetDragOver( transformed_pt, screen_pt, op, ConvertAuraEventFlagsToWebInputEventModifiers(event.flags())); @@ -1237,7 +1264,7 @@ } if (current_rwh_for_drag_) { - current_rwh_for_drag_->DragTargetDragLeave(); + current_rwh_for_drag_->DragTargetDragLeave(gfx::Point(), gfx::Point()); current_rwh_for_drag_.reset(); } @@ -1257,9 +1284,10 @@ if (!IsValidDragTarget(target_rwh)) return ui::DragDropTypes::DRAG_NONE; + gfx::Point screen_pt = display::Screen::GetScreen()->GetCursorScreenPoint(); if (target_rwh != current_rwh_for_drag_.get()) { if (current_rwh_for_drag_) - current_rwh_for_drag_->DragTargetDragLeave(); + current_rwh_for_drag_->DragTargetDragLeave(transformed_pt, screen_pt); OnDragEntered(event); }
diff --git a/content/browser/web_contents/web_drag_dest_mac.mm b/content/browser/web_contents/web_drag_dest_mac.mm index 458b01a..37ed265 100644 --- a/content/browser/web_contents/web_drag_dest_mac.mm +++ b/content/browser/web_contents/web_drag_dest_mac.mm
@@ -10,6 +10,7 @@ #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/renderer_host/render_widget_host_input_event_router.h" +#include "content/browser/renderer_host/render_widget_host_view_base.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_drag_dest_delegate.h" @@ -215,7 +216,7 @@ delegate_->OnDragLeave(); if (currentRWHForDrag_) { - currentRWHForDrag_->DragTargetDragLeave(); + currentRWHForDrag_->DragTargetDragLeave(gfx::Point(), gfx::Point()); currentRWHForDrag_.reset(); } dropData_.reset(); @@ -243,8 +244,23 @@ // TODO(paulmeyer): The dragging delegates may now by invoked multiple times // per drag, even without the drag ever leaving the window. if (targetRWH != currentRWHForDrag_.get()) { - if (currentRWHForDrag_) - currentRWHForDrag_->DragTargetDragLeave(); + if (currentRWHForDrag_) { + gfx::Point transformedLeavePoint = gfx::Point(viewPoint.x, viewPoint.y); + gfx::Point transformedScreenPoint = + gfx::Point(screenPoint.x, screenPoint.y); + content::RenderWidgetHostViewBase* rootView = + static_cast<content::RenderWidgetHostViewBase*>( + webContents_->GetRenderWidgetHostView()); + content::RenderWidgetHostViewBase* currentDragView = + static_cast<content::RenderWidgetHostViewBase*>( + currentRWHForDrag_->GetView()); + rootView->TransformPointToCoordSpaceForView( + transformedLeavePoint, currentDragView, &transformedLeavePoint); + rootView->TransformPointToCoordSpaceForView( + transformedScreenPoint, currentDragView, &transformedScreenPoint); + currentRWHForDrag_->DragTargetDragLeave(transformedLeavePoint, + transformedScreenPoint); + } [self draggingEntered:info view:view]; } @@ -284,7 +300,8 @@ if (targetRWH != currentRWHForDrag_.get()) { if (currentRWHForDrag_) - currentRWHForDrag_->DragTargetDragLeave(); + currentRWHForDrag_->DragTargetDragLeave( + transformedPt, gfx::Point(screenPoint.x, screenPoint.y)); [self draggingEntered:info view:view]; }
diff --git a/content/browser/web_contents/web_drag_source_mac.mm b/content/browser/web_contents/web_drag_source_mac.mm index fdd4649..301fd88 100644 --- a/content/browser/web_contents/web_drag_source_mac.mm +++ b/content/browser/web_contents/web_drag_source_mac.mm
@@ -23,6 +23,7 @@ #include "content/browser/download/drag_download_util.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/renderer_host/render_widget_host_impl.h" +#include "content/browser/renderer_host/render_widget_host_view_base.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/content_browser_client.h" #include "content/public/common/content_client.h" @@ -52,38 +53,6 @@ // |NSURLPboardType|. NSString* const kNSURLTitlePboardType = @"public.url-name"; -// Converts a base::string16 into a FilePath. Use this method instead of -// -[NSString fileSystemRepresentation] to prevent exceptions from being thrown. -// See http://crbug.com/78782 for more info. -base::FilePath FilePathFromFilename(const base::string16& filename) { - NSString* str = SysUTF16ToNSString(filename); - char buf[MAXPATHLEN]; - if (![str getFileSystemRepresentation:buf maxLength:sizeof(buf)]) - return base::FilePath(); - return base::FilePath(buf); -} - -// Returns a filename appropriate for the drop data -// TODO(viettrungluu): Refactor to make it common across platforms, -// and move it somewhere sensible. -base::FilePath GetFileNameFromDragData(const DropData& drop_data) { - base::FilePath file_name( - FilePathFromFilename(drop_data.file_description_filename)); - - // Images without ALT text will only have a file extension so we need to - // synthesize one from the provided extension and URL. - if (file_name.empty()) { - // Retrieve the name from the URL. - base::string16 suggested_filename = - net::GetSuggestedFilename(drop_data.url, "", "", "", "", ""); - const std::string extension = file_name.Extension(); - file_name = FilePathFromFilename(suggested_filename); - file_name = file_name.ReplaceExtension(extension); - } - - return file_name; -} - // This helper's sole task is to write out data for a promised file; the caller // is responsible for opening the file. It takes the drop data and an open file // stream. @@ -291,12 +260,29 @@ if (operation == (NSDragOperationMove | NSDragOperationCopy)) operation &= ~NSDragOperationMove; - // TODO(paulmeyer): In the OOPIF case, should |localPoint| be converted to - // the coordinates local to |dragStartRWH_|? + // |localPoint| and |screenPoint| are in the root coordinate space, for + // non-root RenderWidgetHosts they need to be transformed. + gfx::Point transformedPoint = gfx::Point(localPoint.x, localPoint.y); + gfx::Point transformedScreenPoint = gfx::Point(screenPoint.x, screenPoint.y); + if (dragStartRWH_ && contents_->GetRenderWidgetHostView()) { + content::RenderWidgetHostViewBase* contentsViewBase = + static_cast<content::RenderWidgetHostViewBase*>( + contents_->GetRenderWidgetHostView()); + content::RenderWidgetHostViewBase* dragStartViewBase = + static_cast<content::RenderWidgetHostViewBase*>( + dragStartRWH_->GetView()); + contentsViewBase->TransformPointToCoordSpaceForView( + gfx::Point(localPoint.x, localPoint.y), dragStartViewBase, + &transformedPoint); + contentsViewBase->TransformPointToCoordSpaceForView( + gfx::Point(screenPoint.x, screenPoint.y), dragStartViewBase, + &transformedScreenPoint); + } + contents_->DragSourceEndedAt( - localPoint.x, localPoint.y, screenPoint.x, screenPoint.y, - static_cast<blink::WebDragOperation>(operation), - dragStartRWH_.get()); + transformedPoint.x(), transformedPoint.y(), transformedScreenPoint.x(), + transformedScreenPoint.y(), + static_cast<blink::WebDragOperation>(operation), dragStartRWH_.get()); // Make sure the pasteboard owner isn't us. [pasteboard_ declareTypes:[NSArray array] owner:nil]; @@ -371,8 +357,12 @@ if (!dropData_->file_contents.empty() || !dropData_->download_metadata.empty()) { if (dropData_->download_metadata.empty()) { - downloadFileName_ = GetFileNameFromDragData(*dropData_); - net::GetMimeTypeFromExtension(downloadFileName_.Extension(), &mimeType); + base::Optional<base::FilePath> suggestedFilename = + dropData_->GetSafeFilenameForImageFileContents(); + if (suggestedFilename) { + downloadFileName_ = std::move(*suggestedFilename); + net::GetMimeTypeFromExtension(downloadFileName_.Extension(), &mimeType); + } } else { base::string16 mimeType16; base::FilePath fileName;
diff --git a/content/child/OWNERS b/content/child/OWNERS index f04dee2..a0281e6a 100644 --- a/content/child/OWNERS +++ b/content/child/OWNERS
@@ -1,6 +1,9 @@ # For Blink API usage esprehn@chromium.org +# For resource loading +yhirano@chromium.org + # AppCache per-file appcache*=michaeln@chromium.org
diff --git a/content/child/child_thread_impl.h b/content/child/child_thread_impl.h index a9ce450..012cb43 100644 --- a/content/child/child_thread_impl.h +++ b/content/child/child_thread_impl.h
@@ -27,6 +27,7 @@ #include "ipc/message_router.h" #include "mojo/public/cpp/bindings/associated_binding.h" #include "mojo/public/cpp/bindings/associated_binding_set.h" +#include "services/service_manager/public/cpp/service_info.h" namespace base { class MessageLoop;
diff --git a/content/child/indexed_db/webidbdatabase_impl.cc b/content/child/indexed_db/webidbdatabase_impl.cc index df09767..76179f5 100644 --- a/content/child/indexed_db/webidbdatabase_impl.cc +++ b/content/child/indexed_db/webidbdatabase_impl.cc
@@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "base/format_macros.h" #include "base/memory/ptr_util.h" #include "base/strings/string16.h" #include "base/strings/stringprintf.h"
diff --git a/content/child/web_url_loader_impl.cc b/content/child/web_url_loader_impl.cc index e80f946..1d70521d 100644 --- a/content/child/web_url_loader_impl.cc +++ b/content/child/web_url_loader_impl.cc
@@ -1164,19 +1164,6 @@ response->setHTTPStatusCode(headers->response_code()); response->setHTTPStatusText(WebString::fromLatin1(headers->GetStatusText())); - // TODO(darin): We should leverage HttpResponseHeaders for this, and this - // should be using the same code as ResourceDispatcherHost. - // TODO(jungshik): Figure out the actual value of the referrer charset and - // pass it to GetSuggestedFilename. - std::string value; - headers->EnumerateHeader(NULL, "content-disposition", &value); - response->setSuggestedFileName(blink::WebString::fromUTF16( - net::GetSuggestedFilename(url, value, - std::string(), // referrer_charset - std::string(), // suggested_name - std::string(), // mime_type - std::string()))); // default_name - Time time_val; if (headers->GetLastModifiedValue(&time_val)) response->setLastModifiedDate(time_val.ToDoubleT()); @@ -1184,6 +1171,7 @@ // Build up the header map. size_t iter = 0; std::string name; + std::string value; while (headers->EnumerateHeaderLines(&iter, &name, &value)) { response->addHTTPHeaderField(WebString::fromLatin1(name), WebString::fromLatin1(value));
diff --git a/content/common/DEPS b/content/common/DEPS index eb672f5..d6b4b679 100644 --- a/content/common/DEPS +++ b/content/common/DEPS
@@ -2,6 +2,7 @@ "-storage/browser", "+components/discardable_memory/common", + "+components/payments", "+device/base/synchronization", "+services/service_manager/public/cpp", "+services/video_capture/public/interfaces", @@ -51,6 +52,7 @@ "+third_party/WebKit/public/platform/modules/screen_orientation/WebLockOrientationError.h", "+third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h", "+third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationType.h", + "+third_party/WebKit/public/platform/modules/payments/WebPaymentAppRequest.h", "+third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerCacheError.h", "+third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerClientType.h", "+third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerError.h",
diff --git a/content/common/drag_messages.h b/content/common/drag_messages.h index 0164368..d1b50db 100644 --- a/content/common/drag_messages.h +++ b/content/common/drag_messages.h
@@ -32,7 +32,9 @@ blink::WebDragOperationsMask /* ops_allowed */, int /* key_modifiers */) -IPC_MESSAGE_ROUTED0(DragMsg_TargetDragLeave) +IPC_MESSAGE_ROUTED2(DragMsg_TargetDragLeave, + gfx::Point /* client_point */, + gfx::Point /* screen_point */) IPC_MESSAGE_ROUTED4(DragMsg_TargetDrop, content::DropData /* drop_data */,
diff --git a/content/common/drag_traits.h b/content/common/drag_traits.h index 5f9d151..bf20e175 100644 --- a/content/common/drag_traits.h +++ b/content/common/drag_traits.h
@@ -34,8 +34,9 @@ IPC_STRUCT_TRAITS_MEMBER(text) IPC_STRUCT_TRAITS_MEMBER(html) IPC_STRUCT_TRAITS_MEMBER(html_base_url) - IPC_STRUCT_TRAITS_MEMBER(file_description_filename) IPC_STRUCT_TRAITS_MEMBER(file_contents) + IPC_STRUCT_TRAITS_MEMBER(file_contents_filename_extension) + IPC_STRUCT_TRAITS_MEMBER(file_contents_content_disposition) IPC_STRUCT_TRAITS_MEMBER(custom_data) IPC_STRUCT_TRAITS_END()
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h index 872b38c..2eea1d1 100644 --- a/content/common/frame_messages.h +++ b/content/common/frame_messages.h
@@ -743,6 +743,12 @@ IPC_MESSAGE_ROUTED1(FrameMsg_TextSurroundingSelectionRequest, uint32_t /* max_length */) +// Extracts the data at the given rect, returning it through the +// SmartClipDataExtracted IPC. +IPC_MESSAGE_ROUTED2(FrameMsg_ExtractSmartClipData, + uint32_t /* id */, + gfx::Rect /* rect */) + // Requests information about currently focused text input element from the // renderer. IPC_MESSAGE_ROUTED1(FrameMsg_FocusedFormFieldDataRequest, int /* request_id */) @@ -1443,6 +1449,12 @@ // The message is delivered using RenderWidget::QueueMessage. IPC_MESSAGE_ROUTED1(FrameHostMsg_VisualStateResponse, uint64_t /* id */) +// Reply to the ExtractSmartClipData message. +IPC_MESSAGE_ROUTED3(FrameHostMsg_SmartClipDataExtracted, + uint32_t /* id */, + base::string16 /* text */, + base::string16 /* html */) + // Puts the browser into "tab fullscreen" mode for the sending renderer. // See the comment in chrome/browser/ui/browser.h for more details. IPC_MESSAGE_ROUTED1(FrameHostMsg_ToggleFullscreen, bool /* enter_fullscreen */)
diff --git a/content/common/indexed_db/indexed_db_struct_traits.cc b/content/common/indexed_db/indexed_db_struct_traits.cc index ecd1e675..85d5fe60 100644 --- a/content/common/indexed_db/indexed_db_struct_traits.cc +++ b/content/common/indexed_db/indexed_db_struct_traits.cc
@@ -3,6 +3,8 @@ // found in the LICENSE file. #include "content/common/indexed_db/indexed_db_struct_traits.h" + +#include "base/stl_util.h" #include "mojo/common/common_custom_types_struct_traits.h" using content::IndexedDBKey;
diff --git a/content/common/service_worker/OWNERS b/content/common/service_worker/OWNERS index f2edc88..8760ee6 100644 --- a/content/common/service_worker/OWNERS +++ b/content/common/service_worker/OWNERS
@@ -11,5 +11,8 @@ per-file *.mojom=set noparent per-file *.mojom=file://ipc/SECURITY_OWNERS +per-file *_type_converter*.*=set noparent +per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS + # TEAM: worker-dev@chromium.org # COMPONENT: Blink>ServiceWorker
diff --git a/content/common/service_worker/service_worker_type_converters.cc b/content/common/service_worker/service_worker_type_converters.cc index dccda08..e54bbe9 100644 --- a/content/common/service_worker/service_worker_type_converters.cc +++ b/content/common/service_worker/service_worker_type_converters.cc
@@ -29,4 +29,101 @@ return status_code; } +blink::WebPaymentAppRequest +TypeConverter<blink::WebPaymentAppRequest, + payments::mojom::PaymentAppRequestPtr>:: + Convert(const payments::mojom::PaymentAppRequestPtr& input) { + blink::WebPaymentAppRequest output; + + output.origin = blink::WebString::fromUTF8(input->origin.spec()); + + output.methodData = + blink::WebVector<blink::WebPaymentMethodData>(input->methodData.size()); + for (size_t i = 0; i < input->methodData.size(); i++) { + output.methodData[i] = mojo::ConvertTo<blink::WebPaymentMethodData>( + std::move(input->methodData[i])); + } + + output.total = mojo::ConvertTo<blink::WebPaymentItem>(input->total); + + output.modifiers = blink::WebVector<blink::WebPaymentDetailsModifier>( + input->modifiers.size()); + for (size_t i = 0; i < input->modifiers.size(); i++) { + output.modifiers[i] = + mojo::ConvertTo<blink::WebPaymentDetailsModifier>(input->modifiers[i]); + } + + output.optionId = blink::WebString::fromUTF8(input->optionId); + + return output; +} + +blink::WebPaymentMethodData +TypeConverter<blink::WebPaymentMethodData, + payments::mojom::PaymentMethodDataPtr>:: + Convert(const payments::mojom::PaymentMethodDataPtr& input) { + blink::WebPaymentMethodData output; + + output.supportedMethods = + blink::WebVector<blink::WebString>(input->supported_methods.size()); + for (size_t i = 0; i < input->supported_methods.size(); i++) { + output.supportedMethods[i] = + blink::WebString::fromUTF8(input->supported_methods[i]); + } + + output.stringifiedData = blink::WebString::fromUTF8(input->stringified_data); + + return output; +} + +blink::WebPaymentItem +TypeConverter<blink::WebPaymentItem, payments::mojom::PaymentItemPtr>::Convert( + const payments::mojom::PaymentItemPtr& input) { + blink::WebPaymentItem output; + output.label = blink::WebString::fromUTF8(input->label); + output.amount = + mojo::ConvertTo<blink::WebPaymentCurrencyAmount>(input->amount); + output.pending = input->pending; + return output; +} + +blink::WebPaymentCurrencyAmount +TypeConverter<blink::WebPaymentCurrencyAmount, + payments::mojom::PaymentCurrencyAmountPtr>:: + Convert(const payments::mojom::PaymentCurrencyAmountPtr& input) { + blink::WebPaymentCurrencyAmount output; + output.currency = blink::WebString::fromUTF8(input->currency); + output.value = blink::WebString::fromUTF8(input->value); + output.currencySystem = blink::WebString::fromUTF8(input->currency_system); + return output; +} + +blink::WebPaymentDetailsModifier +TypeConverter<blink::WebPaymentDetailsModifier, + payments::mojom::PaymentDetailsModifierPtr>:: + Convert(const payments::mojom::PaymentDetailsModifierPtr& input) { + blink::WebPaymentDetailsModifier output; + + output.supportedMethods = blink::WebVector<blink::WebString>( + input->method_data->supported_methods.size()); + for (size_t i = 0; i < input->method_data->supported_methods.size(); i++) { + output.supportedMethods[i] = + blink::WebString::fromUTF8(input->method_data->supported_methods[i]); + } + + output.total = mojo::ConvertTo<blink::WebPaymentItem>(input->total); + + output.additionalDisplayItems = blink::WebVector<blink::WebPaymentItem>( + input->additional_display_items.size()); + for (size_t i = 0; i < input->additional_display_items.size(); i++) { + output.additionalDisplayItems[i] = mojo::ConvertTo<blink::WebPaymentItem>( + input->additional_display_items[i]); + } + + output.stringifiedData = + blink::WebString::fromUTF8(input->method_data->stringified_data); + + return output; +} + } // namespace
diff --git a/content/common/service_worker/service_worker_type_converters.h b/content/common/service_worker/service_worker_type_converters.h index 78c46e5ad..777d91c 100644 --- a/content/common/service_worker/service_worker_type_converters.h +++ b/content/common/service_worker/service_worker_type_converters.h
@@ -5,7 +5,9 @@ #ifndef CONTENT_COMMON_SERVICE_WORKER_SERVICE_WORKER_TYPE_CONVERTERS_H_ #define CONTENT_COMMON_SERVICE_WORKER_SERVICE_WORKER_TYPE_CONVERTERS_H_ +#include "components/payments/payment_app.mojom.h" #include "content/common/service_worker/service_worker_status_code.h" +#include "third_party/WebKit/public/platform/modules/payments/WebPaymentAppRequest.h" #include "third_party/WebKit/public/platform/modules/serviceworker/service_worker_event_status.mojom.h" namespace mojo { @@ -17,6 +19,40 @@ blink::mojom::ServiceWorkerEventStatus status); }; +template <> +struct TypeConverter<blink::WebPaymentAppRequest, + payments::mojom::PaymentAppRequestPtr> { + static blink::WebPaymentAppRequest Convert( + const payments::mojom::PaymentAppRequestPtr& input); +}; + +template <> +struct TypeConverter<blink::WebPaymentMethodData, + payments::mojom::PaymentMethodDataPtr> { + static blink::WebPaymentMethodData Convert( + const payments::mojom::PaymentMethodDataPtr& input); +}; + +template <> +struct TypeConverter<blink::WebPaymentItem, payments::mojom::PaymentItemPtr> { + static blink::WebPaymentItem Convert( + const payments::mojom::PaymentItemPtr& input); +}; + +template <> +struct TypeConverter<blink::WebPaymentCurrencyAmount, + payments::mojom::PaymentCurrencyAmountPtr> { + static blink::WebPaymentCurrencyAmount Convert( + const payments::mojom::PaymentCurrencyAmountPtr& input); +}; + +template <> +struct TypeConverter<blink::WebPaymentDetailsModifier, + payments::mojom::PaymentDetailsModifierPtr> { + static blink::WebPaymentDetailsModifier Convert( + const payments::mojom::PaymentDetailsModifierPtr& input); +}; + } // namespace #endif // CONTENT_COMMON_SERVICE_WORKER_SERVICE_WORKER_TYPE_CONVERTERS_H_
diff --git a/content/common/site_isolation_policy.cc b/content/common/site_isolation_policy.cc index 5a47487..a1607c84 100644 --- a/content/common/site_isolation_policy.cc +++ b/content/common/site_isolation_policy.cc
@@ -5,21 +5,13 @@ #include "content/common/site_isolation_policy.h" #include "base/command_line.h" -#include "base/feature_list.h" -#include "base/lazy_instance.h" -#include "content/public/common/browser_side_navigation_policy.h" -#include "content/public/common/content_client.h" -#include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" namespace content { // static bool SiteIsolationPolicy::AreCrossProcessFramesPossible() { - return UseDedicatedProcessesForAllSites() || - IsTopDocumentIsolationEnabled() || - GetContentClient()->IsSupplementarySiteIsolationModeEnabled() || - base::FeatureList::IsEnabled(::features::kGuestViewCrossProcessFrames); + return true; } // static
diff --git a/content/common/view_messages.h b/content/common/view_messages.h index f12fa45f..3b7b3c4 100644 --- a/content/common/view_messages.h +++ b/content/common/view_messages.h
@@ -574,10 +574,6 @@ bool /* enable_showing */, bool /* animate */) -// Extracts the data at the given rect, returning it through the -// ViewHostMsg_SmartClipDataExtracted IPC. -IPC_MESSAGE_ROUTED1(ViewMsg_ExtractSmartClipData, - gfx::Rect /* rect */) #endif // Sent by browser to tell renderer compositor that some resources that were @@ -869,12 +865,6 @@ GURL /* content_url */, bool /* is_main_frame */) -// Reply to the ViewMsg_ExtractSmartClipData message. -IPC_MESSAGE_ROUTED3(ViewHostMsg_SmartClipDataExtracted, - base::string16 /* text */, - base::string16 /* html */, - gfx::Rect /* rect */) - // Notifies that an unhandled tap has occurred at the specified x,y position // and that the UI may need to be triggered. IPC_MESSAGE_ROUTED2(ViewHostMsg_ShowUnhandledTapUIIfNeeded,
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn index d6e5162..88b8058 100644 --- a/content/public/android/BUILD.gn +++ b/content/public/android/BUILD.gn
@@ -229,6 +229,7 @@ "java/src/org/chromium/content_public/browser/NavigationController.java", "java/src/org/chromium/content_public/browser/NavigationEntry.java", "java/src/org/chromium/content_public/browser/NavigationHistory.java", + "java/src/org/chromium/content_public/browser/SmartClipCallback.java", "java/src/org/chromium/content_public/browser/WebContents.java", "java/src/org/chromium/content_public/browser/WebContentsObserver.java", "java/src/org/chromium/content_public/common/MediaMetadata.java",
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentView.java b/content/public/android/java/src/org/chromium/content/browser/ContentView.java index a0857e0..cff01aa 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ContentView.java +++ b/content/public/android/java/src/org/chromium/content/browser/ContentView.java
@@ -10,7 +10,6 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.os.Message; import android.view.DragEvent; import android.view.KeyEvent; import android.view.MotionEvent; @@ -22,7 +21,6 @@ import android.view.inputmethod.InputConnection; import android.widget.FrameLayout; -import org.chromium.base.Log; import org.chromium.base.TraceEvent; /** @@ -291,34 +289,16 @@ // Implements SmartClipProvider @Override public void extractSmartClipData(int x, int y, int width, int height) { - mContentViewCore.extractSmartClipData(x, y, width, height); + float dpi = mContentViewCore.getRenderCoordinates().getDeviceScaleFactor(); + y -= mContentViewCore.getRenderCoordinates().getContentOffsetYPix(); + mContentViewCore.getWebContents().requestSmartClipExtract( + (int) (x / dpi), (int) (y / dpi), (int) (width / dpi), (int) (height / dpi)); } // Implements SmartClipProvider @Override public void setSmartClipResultHandler(final Handler resultHandler) { - if (resultHandler == null) { - mContentViewCore.setSmartClipDataListener(null); - return; - } - mContentViewCore.setSmartClipDataListener(new ContentViewCore.SmartClipDataListener() { - @Override - public void onSmartClipDataExtracted(String text, String html, Rect clipRect) { - Bundle bundle = new Bundle(); - bundle.putString("url", mContentViewCore.getWebContents().getVisibleUrl()); - bundle.putString("title", mContentViewCore.getWebContents().getTitle()); - bundle.putParcelable("rect", clipRect); - bundle.putString("text", text); - bundle.putString("html", html); - try { - Message msg = Message.obtain(resultHandler, 0); - msg.setData(bundle); - msg.sendToTarget(); - } catch (Exception e) { - Log.e(TAG, "Error calling handler for smart clip data: ", e); - } - } - }); + mContentViewCore.getWebContents().setSmartClipResultHandler(resultHandler); } ///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java index 9f97f23..78232fa 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java +++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -263,14 +263,6 @@ boolean super_awakenScrollBars(int startDelay, boolean invalidate); } - /** - * An interface that allows the embedder to be notified when the results of - * extractSmartClipData are available. - */ - public interface SmartClipDataListener { - public void onSmartClipDataExtracted(String text, String html, Rect clipRect); - } - private final Context mContext; private final String mProductVersion; private ViewGroup mContainerView; @@ -359,8 +351,6 @@ // onNativeFlingStopped() is called asynchronously. private int mPotentiallyActiveFlingCount; - private SmartClipDataListener mSmartClipDataListener; - /** * PID used to indicate an invalid render process. */ @@ -372,10 +362,6 @@ private float mCurrentTouchOffsetX; private float mCurrentTouchOffsetY; - // Offsets for smart clip - private int mSmartClipOffsetX; - private int mSmartClipOffsetY; - // Whether the ContentViewCore requires the WebContents to be fullscreen in order to lock the // screen orientation. private boolean mFullscreenRequiredForOrientationLock = true; @@ -792,7 +778,6 @@ } mWebContentsObserver.destroy(); mWebContentsObserver = null; - setSmartClipDataListener(null); mImeAdapter.resetAndHideKeyboard(); // TODO(igsolla): address TODO in ContentViewClient because ContentViewClient is not // currently a real Null Object. @@ -2565,52 +2550,6 @@ return new Rect(x, y, right, bottom); } - public void extractSmartClipData(int x, int y, int width, int height) { - if (mNativeContentViewCore != 0) { - x += mSmartClipOffsetX; - y += mSmartClipOffsetY; - nativeExtractSmartClipData(mNativeContentViewCore, x, y, width, height); - } - } - - /** - * Set offsets for smart clip. - * - * <p>This should be called if there is a viewport change introduced by, - * e.g., show and hide of a location bar. - * - * @param offsetX Offset for X position. - * @param offsetY Offset for Y position. - */ - public void setSmartClipOffsets(int offsetX, int offsetY) { - mSmartClipOffsetX = offsetX; - mSmartClipOffsetY = offsetY; - } - - @CalledByNative - private void onSmartClipDataExtracted(String text, String html, Rect clipRect) { - // Translate the positions by the offsets introduced by location bar. Note that the - // coordinates are in dp scale, and that this definitely has the potential to be - // different from the offsets when extractSmartClipData() was called. However, - // as long as OEM has a UI that consumes all the inputs and waits until the - // callback is called, then there shouldn't be any difference. - // TODO(changwan): once crbug.com/416432 is resolved, try to pass offsets as - // separate params for extractSmartClipData(), and apply them not the new offset - // values in the callback. - final float deviceScale = mRenderCoordinates.getDeviceScaleFactor(); - final int offsetXInDp = (int) (mSmartClipOffsetX / deviceScale); - final int offsetYInDp = (int) (mSmartClipOffsetY / deviceScale); - clipRect.offset(-offsetXInDp, -offsetYInDp); - - if (mSmartClipDataListener != null) { - mSmartClipDataListener.onSmartClipDataExtracted(text, html, clipRect); - } - } - - public void setSmartClipDataListener(SmartClipDataListener listener) { - mSmartClipDataListener = listener; - } - public void setBackgroundOpaque(boolean opaque) { if (mNativeContentViewCore != 0) { nativeSetBackgroundOpaque(mNativeContentViewCore, opaque); @@ -2907,9 +2846,6 @@ String textTrackFontStyle, String textTrackFontVariant, String textTrackTextColor, String textTrackTextShadow, String textTrackTextSize); - private native void nativeExtractSmartClipData(long nativeContentViewCoreImpl, - int x, int y, int w, int h); - private native void nativeSetBackgroundOpaque(long nativeContentViewCoreImpl, boolean opaque); private native boolean nativeIsTouchDragDropEnabled(long nativeContentViewCoreImpl); private native void nativeOnDragEvent(long nativeContentViewCoreImpl, int action, int x, int y,
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/Range.java b/content/public/android/java/src/org/chromium/content/browser/input/Range.java index dba86c4..16019d4 100644 --- a/content/public/android/java/src/org/chromium/content/browser/input/Range.java +++ b/content/public/android/java/src/org/chromium/content/browser/input/Range.java
@@ -12,7 +12,7 @@ * version becomes 21 or higher. */ public class Range { - private int mStart; + private int mStart; // guaranteed to be smaller than or equal to mEnd private int mEnd; public Range(int start, int end) { @@ -38,6 +38,10 @@ mEnd = Math.max(Math.min(mEnd, end), start); } + public boolean intersects(Range range) { + return mStart <= range.mEnd && mEnd >= range.mStart; + } + @Override public boolean equals(Object o) { if (!(o instanceof Range)) return false;
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java index 5150f32..b7dc506 100644 --- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
@@ -8,6 +8,8 @@ import android.graphics.Bitmap; import android.graphics.Rect; import android.os.Bundle; +import android.os.Handler; +import android.os.Message; import android.os.Parcel; import android.os.ParcelUuid; import android.os.Parcelable; @@ -26,6 +28,7 @@ import org.chromium.content_public.browser.JavaScriptCallback; import org.chromium.content_public.browser.MessagePortService; import org.chromium.content_public.browser.NavigationController; +import org.chromium.content_public.browser.SmartClipCallback; import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContentsObserver; import org.chromium.ui.OverscrollRefreshHandler; @@ -99,6 +102,8 @@ // the same life time as native MediaSession. private MediaSessionImpl mMediaSession; + private SmartClipCallback mSmartClipCallback; + private WebContentsImpl( long nativeWebContentsAndroid, NavigationController navigationController) { mNativeWebContentsAndroid = nativeWebContentsAndroid; @@ -367,6 +372,41 @@ } @Override + public void requestSmartClipExtract(int x, int y, int width, int height) { + assert mSmartClipCallback != null; + nativeRequestSmartClipExtract( + mNativeWebContentsAndroid, mSmartClipCallback, x, y, width, height); + } + + @Override + public void setSmartClipResultHandler(final Handler smartClipHandler) { + if (smartClipHandler == null) { + mSmartClipCallback = null; + return; + } + mSmartClipCallback = new SmartClipCallback() { + @Override + public void onSmartClipDataExtracted(String text, String html) { + Bundle bundle = new Bundle(); + bundle.putString("url", getVisibleUrl()); + bundle.putString("title", getTitle()); + bundle.putString("text", text); + bundle.putString("html", html); + + Message msg = Message.obtain(smartClipHandler, 0); + msg.setData(bundle); + msg.sendToTarget(); + } + }; + } + + @CalledByNative + private static void onSmartClipDataExtracted( + String text, String html, SmartClipCallback callback) { + callback.onSmartClipDataExtracted(text, html); + } + + @Override public void requestAccessibilitySnapshot(AccessibilitySnapshotCallback callback) { nativeRequestAccessibilitySnapshot(mNativeWebContentsAndroid, callback); } @@ -545,6 +585,8 @@ private native boolean nativeHasAccessedInitialDocument( long nativeWebContentsAndroid); private native int nativeGetThemeColor(long nativeWebContentsAndroid); + private native void nativeRequestSmartClipExtract(long nativeWebContentsAndroid, + SmartClipCallback callback, int x, int y, int width, int height); private native void nativeRequestAccessibilitySnapshot( long nativeWebContentsAndroid, AccessibilitySnapshotCallback callback); private native void nativeSetOverscrollRefreshHandler(
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/SmartClipCallback.java b/content/public/android/java/src/org/chromium/content_public/browser/SmartClipCallback.java new file mode 100644 index 0000000..e92a5ad5 --- /dev/null +++ b/content/public/android/java/src/org/chromium/content_public/browser/SmartClipCallback.java
@@ -0,0 +1,13 @@ +// 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. + +package org.chromium.content_public.browser; + +/** + * An interface that allows the embedder to be notified when the results of + * extractSmartClipData are available. + */ +public interface SmartClipCallback { + void onSmartClipDataExtracted(String text, String html); +}
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java index 22bb994..904c05f 100644 --- a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java +++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
@@ -6,6 +6,7 @@ import android.graphics.Bitmap; import android.graphics.Rect; +import android.os.Handler; import android.os.Parcelable; import org.chromium.base.VisibleForTesting; @@ -298,6 +299,17 @@ int getThemeColor(); /** + * Initiate extraction of text, HTML, and other information for clipping puposes (smart clip) + * from the rectangle area defined by starting positions (x and y), and width and height. + */ + void requestSmartClipExtract(int x, int y, int width, int height); + + /** + * Register a handler to handle smart clip data once extraction is done. + */ + void setSmartClipResultHandler(final Handler smartClipHandler); + + /** * Requests a snapshop of accessibility tree. The result is provided asynchronously * using the callback * @param callback The callback to be called when the snapshot is ready. The callback
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java index 4e56ad9..9401829 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
@@ -68,7 +68,39 @@ mSelectionPopupController = mContentViewCore.getSelectionPopupControllerForTesting(); mWebContents = getWebContents(); - mInputMethodManagerWrapper = new TestInputMethodManagerWrapper(mContentViewCore); + mInputMethodManagerWrapper = new TestInputMethodManagerWrapper(mContentViewCore) { + private boolean mExpectsSelectionOutsideComposition; + + @Override + public void expectsSelectionOutsideComposition() { + mExpectsSelectionOutsideComposition = true; + } + + @Override + public void onUpdateSelection( + Range oldSel, Range oldComp, Range newSel, Range newComp) { + // We expect that selection will be outside composition in some cases. Keyboard + // app will not finish composition in this case. + if (mExpectsSelectionOutsideComposition) { + mExpectsSelectionOutsideComposition = false; + return; + } + if (oldComp == null || oldComp.start() == oldComp.end() + || newComp.start() == newComp.end()) { + return; + } + // This emulates keyboard app's behavior that finishes composition when + // selection is outside composition. + if (!newSel.intersects(newComp)) { + try { + finishComposingText(); + } catch (Exception e) { + e.printStackTrace(); + fail(); + } + } + } + }; getImeAdapter().setInputMethodManagerWrapperForTest(mInputMethodManagerWrapper); assertEquals(0, mInputMethodManagerWrapper.getShowSoftInputCounter()); mConnectionFactory = @@ -213,6 +245,25 @@ @SmallTest @Feature({"TextInput", "Main"}) + public void testKeyboardAppFinishesCompositionOnUnexpectedSelectionChange() throws Throwable { + focusElementAndWaitForStateUpdate("textarea"); + commitText("12345", 1); + setSelection(3, 3); + setComposingRegion(2, 3); + + waitAndVerifyUpdateSelection(0, 5, 5, -1, -1); + waitAndVerifyUpdateSelection(1, 3, 3, -1, -1); + waitAndVerifyUpdateSelection(2, 3, 3, 2, 3); + + // Unexpected selection change occurs, e.g., the user clicks on an area. + DOMUtils.clickNode(this, mContentViewCore, "textarea"); + waitAndVerifyUpdateSelection(3, 5, 5, 2, 3); + // Keyboard app finishes composition. We emulate this in TestInputMethodManagerWrapper. + waitAndVerifyUpdateSelection(4, 5, 5, -1, -1); + } + + @SmallTest + @Feature({"TextInput", "Main"}) public void testSetComposingTextForNewCursorPositions() throws Throwable { // Cursor is on the right of composing text when newCursorPosition > 0. setComposingText("ab", 1); @@ -226,9 +277,11 @@ waitAndVerifyUpdateSelection(2, 0, 0, 2, 6); // Cursor is on the left boundary. + mInputMethodManagerWrapper.expectsSelectionOutsideComposition(); setComposingText("cd", -2); waitAndVerifyUpdateSelection(3, 0, 0, 2, 4); + mInputMethodManagerWrapper.expectsSelectionOutsideComposition(); // Cursor is between the left boundary and the composing text. setComposingText("cd", -1); waitAndVerifyUpdateSelection(4, 1, 1, 2, 4); @@ -244,14 +297,17 @@ setComposingText("ef", 1); waitAndVerifyUpdateSelection(7, 4, 4, 2, 4); + mInputMethodManagerWrapper.expectsSelectionOutsideComposition(); // Cursor is between the composing text and the right boundary. setComposingText("ef", 2); waitAndVerifyUpdateSelection(8, 5, 5, 2, 4); + mInputMethodManagerWrapper.expectsSelectionOutsideComposition(); // Cursor is on the right boundary. setComposingText("ef", 3); waitAndVerifyUpdateSelection(9, 6, 6, 2, 4); + mInputMethodManagerWrapper.expectsSelectionOutsideComposition(); // Cursor exceeds the right boundary. setComposingText("efgh", 100); waitAndVerifyUpdateSelection(10, 8, 8, 2, 6);
diff --git a/content/public/android/junit/src/org/chromium/content/browser/input/RangeTest.java b/content/public/android/junit/src/org/chromium/content/browser/input/RangeTest.java index d5ef8eb5..cb545c33 100644 --- a/content/public/android/junit/src/org/chromium/content/browser/input/RangeTest.java +++ b/content/public/android/junit/src/org/chromium/content/browser/input/RangeTest.java
@@ -8,11 +8,12 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import org.chromium.base.test.util.Feature; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.BlockJUnit4ClassRunner; +import org.chromium.base.test.util.Feature; + /** * Unit tests for {@Range}. */ @@ -47,4 +48,20 @@ Range range = new Range(1, 4); assertTrue(range.equals(range)); } + + @Test + @Feature({"TextInput"}) + public void testIntersects() { + assertTrue(new Range(1, 3).intersects(new Range(0, 2))); + assertTrue(new Range(0, 2).intersects(new Range(1, 3))); + + assertTrue(new Range(0, 2).intersects(new Range(2, 3))); + assertTrue(new Range(2, 3).intersects(new Range(0, 2))); + + assertFalse(new Range(1, 3).intersects(new Range(4, 6))); + assertFalse(new Range(4, 6).intersects(new Range(1, 3))); + + Range range = new Range(1, 3); + assertTrue(range.intersects(range)); + } } \ No newline at end of file
diff --git a/content/public/app/content_jni_onload.h b/content/public/app/content_jni_onload.h index 1b220f5..0f449ea5 100644 --- a/content/public/app/content_jni_onload.h +++ b/content/public/app/content_jni_onload.h
@@ -14,13 +14,10 @@ namespace android { // Returns true if JNI registration succeeded. -CONTENT_EXPORT bool OnJNIOnLoadRegisterJNI( - JavaVM* vm, - std::vector<base::android::RegisterCallback> callbacks); +CONTENT_EXPORT bool OnJNIOnLoadRegisterJNI(JNIEnv* env); // Returns true if initialization succeeded. -CONTENT_EXPORT bool OnJNIOnLoadInit( - std::vector<base::android::InitCallback> callbacks); +CONTENT_EXPORT bool OnJNIOnLoadInit(); } // namespace android } // namespace content
diff --git a/content/public/browser/browser_thread.h b/content/public/browser/browser_thread.h index e31797a..1fb3e27 100644 --- a/content/public/browser/browser_thread.h +++ b/content/public/browser/browser_thread.h
@@ -6,6 +6,7 @@ #define CONTENT_PUBLIC_BROWSER_BROWSER_THREAD_H_ #include <string> +#include <utility> #include "base/callback.h" #include "base/location.h" @@ -119,22 +120,21 @@ const base::Closure& task, base::TimeDelta delay); - static bool PostTaskAndReply( - ID identifier, - const tracked_objects::Location& from_here, - const base::Closure& task, - const base::Closure& reply); + static bool PostTaskAndReply(ID identifier, + const tracked_objects::Location& from_here, + base::Closure task, + base::Closure reply); template <typename ReturnType, typename ReplyArgType> static bool PostTaskAndReplyWithResult( ID identifier, const tracked_objects::Location& from_here, - const base::Callback<ReturnType(void)>& task, - const base::Callback<void(ReplyArgType)>& reply) { + base::Callback<ReturnType()> task, + base::Callback<void(ReplyArgType)> reply) { scoped_refptr<base::SingleThreadTaskRunner> task_runner = GetTaskRunnerForThread(identifier); - return base::PostTaskAndReplyWithResult(task_runner.get(), from_here, task, - reply); + return base::PostTaskAndReplyWithResult(task_runner.get(), from_here, + std::move(task), std::move(reply)); } template <class T> @@ -176,8 +176,8 @@ const base::Closure& task); static bool PostBlockingPoolTaskAndReply( const tracked_objects::Location& from_here, - const base::Closure& task, - const base::Closure& reply); + base::Closure task, + base::Closure reply); static bool PostBlockingPoolSequencedTask( const std::string& sequence_token_name, const tracked_objects::Location& from_here,
diff --git a/content/public/browser/devtools_external_agent_proxy_delegate.h b/content/public/browser/devtools_external_agent_proxy_delegate.h index 56f44715..137a7db 100644 --- a/content/public/browser/devtools_external_agent_proxy_delegate.h +++ b/content/public/browser/devtools_external_agent_proxy_delegate.h
@@ -51,6 +51,9 @@ // Reloads agent host. virtual bool Close() = 0; + // Returns the time when the host was last active. + virtual base::TimeTicks GetLastActivityTime() = 0; + // Sends a message to the agent. virtual void SendMessageToBackend(const std::string& message) = 0; };
diff --git a/content/public/browser/navigation_handle.h b/content/public/browser/navigation_handle.h index d7d38112..e3e8df8e 100644 --- a/content/public/browser/navigation_handle.h +++ b/content/public/browser/navigation_handle.h
@@ -166,10 +166,12 @@ // there will be one entry in the list). virtual const std::vector<GURL>& GetRedirectChain() = 0; - // Whether the navigation has committed. This returns true for either - // successful commits or error pages that replace the previous page - // (distinguished by |IsErrorPage|), and false for errors that leave the user - // on the previous page. + // Whether the navigation has committed. Navigations that end up being + // downloads or return 204/205 response codes do not commit (i.e. the + // WebContents stays at the existing URL). + // This returns true for either successful commits or error pages that + // replace the previous page (distinguished by |IsErrorPage|), and false for + // errors that leave the user on the previous page. virtual bool HasCommitted() = 0; // Whether the navigation resulted in an error page.
diff --git a/content/public/browser/render_widget_host.h b/content/public/browser/render_widget_host.h index 059f9e04f..48336e4 100644 --- a/content/public/browser/render_widget_host.h +++ b/content/public/browser/render_widget_host.h
@@ -276,7 +276,8 @@ const gfx::Point& screen_pt, blink::WebDragOperationsMask operations_allowed, int key_modifiers) {} - virtual void DragTargetDragLeave() {} + virtual void DragTargetDragLeave(const gfx::Point& client_point, + const gfx::Point& screen_point) {} virtual void DragTargetDrop(const DropData& drop_data, const gfx::Point& client_pt, const gfx::Point& screen_pt,
diff --git a/content/public/browser/screen_orientation_provider.cc b/content/public/browser/screen_orientation_provider.cc index 7da24eb..db08e33 100644 --- a/content/public/browser/screen_orientation_provider.cc +++ b/content/public/browser/screen_orientation_provider.cc
@@ -7,6 +7,7 @@ #include "base/callback_helpers.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/browser/navigation_handle.h" #include "content/public/browser/render_widget_host.h" #include "content/public/browser/screen_orientation_delegate.h" #include "content/public/browser/web_contents.h" @@ -19,7 +20,9 @@ ScreenOrientationDelegate* ScreenOrientationProvider::delegate_ = nullptr; ScreenOrientationProvider::ScreenOrientationProvider(WebContents* web_contents) - : WebContentsObserver(web_contents), lock_applied_(false) {} + : WebContentsObserver(web_contents), + lock_applied_(false), + bindings_(web_contents, this) {} ScreenOrientationProvider::~ScreenOrientationProvider() { } @@ -106,9 +109,9 @@ void ScreenOrientationProvider::NotifyLockResult( ScreenOrientationLockResult result) { - if (!pending_callback_.is_null()) { + if (!pending_callback_.is_null()) base::ResetAndReturn(&pending_callback_).Run(result); - } + pending_lock_orientation_.reset(); } @@ -131,6 +134,15 @@ UnlockOrientation(); } +void ScreenOrientationProvider::DidFinishNavigation( + NavigationHandle* navigation_handle) { + if (!navigation_handle->IsInMainFrame() || + !navigation_handle->HasCommitted() || navigation_handle->IsSamePage()) { + return; + } + UnlockOrientation(); +} + blink::WebScreenOrientationLockType ScreenOrientationProvider::GetNaturalLockType() const { RenderWidgetHost* rwh = web_contents()->GetRenderViewHost()->GetWidget();
diff --git a/content/public/browser/screen_orientation_provider.h b/content/public/browser/screen_orientation_provider.h index 1ee9d82..78cbe55 100644 --- a/content/public/browser/screen_orientation_provider.h +++ b/content/public/browser/screen_orientation_provider.h
@@ -6,10 +6,13 @@ #define CONTENT_PUBLIC_BROWSER_SCREEN_ORIENTATION_PROVIDER_H_ #include "base/callback.h" +#include "base/compiler_specific.h" #include "base/macros.h" #include "base/optional.h" #include "content/common/content_export.h" +#include "content/public/browser/web_contents_binding_set.h" #include "content/public/browser/web_contents_observer.h" +#include "device/screen_orientation/public/interfaces/screen_orientation.mojom.h" #include "device/screen_orientation/public/interfaces/screen_orientation_lock_types.mojom.h" #include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h" @@ -18,24 +21,20 @@ class ScreenOrientationDelegate; class WebContents; -using LockOrientationCallback = - base::Callback<void(device::mojom::ScreenOrientationLockResult)>; - // Handles screen orientation lock/unlock. Platforms which wish to provide // custom implementations can provide a factory for ScreenOrientationDelegate. -class CONTENT_EXPORT ScreenOrientationProvider : public WebContentsObserver { +class CONTENT_EXPORT ScreenOrientationProvider + : NON_EXPORTED_BASE(public device::mojom::ScreenOrientation), + public WebContentsObserver { public: ScreenOrientationProvider(WebContents* web_contents); ~ScreenOrientationProvider() override; - // Lock the screen orientation to |orientation|, |callback| is the callback - // that should be invoked when this request receives a result. + // device::mojom::ScreenOrientation: void LockOrientation(blink::WebScreenOrientationLockType orientation, - const LockOrientationCallback& callback); - - // Unlock the screen orientation. - void UnlockOrientation(); + const LockOrientationCallback& callback) override; + void UnlockOrientation() override; // Inform about a screen orientation update. It is called to let the provider // know if a lock has been resolved. @@ -48,6 +47,7 @@ // WebContentsObserver void DidToggleFullscreenModeForTab(bool entered_fullscreen, bool will_cause_resize) override; + void DidFinishNavigation(NavigationHandle* navigation_handle) override; private: // Calls on |on_result_callback_| with |result|, followed by resetting @@ -69,12 +69,14 @@ // Whether the ScreenOrientationProvider currently has a lock applied. bool lock_applied_; - // Locks that require orientation changes are not completed until + // Lock that require orientation changes are not completed until // OnOrientationChange. base::Optional<blink::WebScreenOrientationLockType> pending_lock_orientation_; LockOrientationCallback pending_callback_; + WebContentsFrameBindingSet<device::mojom::ScreenOrientation> bindings_; + DISALLOW_COPY_AND_ASSIGN(ScreenOrientationProvider); };
diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn index f04b7f90f..addcdcbb 100644 --- a/content/public/common/BUILD.gn +++ b/content/public/common/BUILD.gn
@@ -259,6 +259,7 @@ deps = [ # This looks needless as we have //content/common in public_deps, but it's # needed because of allow_circular_includes_from. + "//components/mime_util", "//content/common:mojo_bindings", "//ipc", "//media",
diff --git a/content/public/common/DEPS b/content/public/common/DEPS index 2fd1c5f..7069861 100644 --- a/content/public/common/DEPS +++ b/content/public/common/DEPS
@@ -1,5 +1,6 @@ specific_include_rules = { ".*\.cc": [ "+content/common", + "+components/mime_util", ], }
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index b4673583..e3b0d9fe 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -266,6 +266,10 @@ base::FEATURE_DISABLED_BY_DEFAULT}; #if defined(OS_ANDROID) +// A browsing history manager implementation for Android. +const base::Feature kNativeAndroidHistoryManager{ + "AndroidHistoryManager", base::FEATURE_DISABLED_BY_DEFAULT}; + // FeatureList definition for the Seccomp field trial. const base::Feature kSeccompSandboxAndroid{"SeccompSandboxAndroid", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 8a82b65..bc8a60d1 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -71,6 +71,7 @@ extern const base::Feature kSendBeaconThrowForBlobWithNonSimpleType; #if defined(OS_ANDROID) +CONTENT_EXPORT extern const base::Feature kNativeAndroidHistoryManager; CONTENT_EXPORT extern const base::Feature kImeThread; CONTENT_EXPORT extern const base::Feature kSeccompSandboxAndroid; CONTENT_EXPORT extern const base::Feature kServiceWorkerPaymentApps;
diff --git a/content/public/common/drop_data.cc b/content/public/common/drop_data.cc index ef881cc..ac562e8 100644 --- a/content/public/common/drop_data.cc +++ b/content/public/common/drop_data.cc
@@ -4,18 +4,13 @@ #include "content/public/common/drop_data.h" +#include "base/strings/utf_string_conversions.h" +#include "components/mime_util/mime_util.h" +#include "net/base/filename_util.h" +#include "net/base/mime_util.h" + namespace content { -DropData::DropData() - : did_originate_from_renderer(false), - referrer_policy(blink::WebReferrerPolicyDefault), - key_modifiers(0) {} - -DropData::DropData(const DropData& other) = default; - -DropData::~DropData() { -} - DropData::Metadata::Metadata() {} // static @@ -50,4 +45,30 @@ DropData::Metadata::~Metadata() {} +DropData::DropData() + : did_originate_from_renderer(false), + referrer_policy(blink::WebReferrerPolicyDefault), + key_modifiers(0) {} + +DropData::DropData(const DropData& other) = default; + +DropData::~DropData() {} + +base::Optional<base::FilePath> DropData::GetSafeFilenameForImageFileContents() + const { + base::FilePath file_name = net::GenerateFileName( + file_contents_source_url, file_contents_content_disposition, + std::string(), // referrer_charset + std::string(), // suggested_name + std::string(), // mime_type + std::string()); // default_name + std::string mime_type; + if (net::GetWellKnownMimeTypeFromExtension(file_contents_filename_extension, + &mime_type) && + mime_util::IsSupportedImageMimeType(mime_type)) { + return file_name.ReplaceExtension(file_contents_filename_extension); + } + return base::nullopt; +} + } // namespace content
diff --git a/content/public/common/drop_data.h b/content/public/common/drop_data.h index a5439b6..204d671 100644 --- a/content/public/common/drop_data.h +++ b/content/public/common/drop_data.h
@@ -15,6 +15,8 @@ #include <string> #include <vector> +#include "base/files/file_path.h" +#include "base/optional.h" #include "base/strings/nullable_string16.h" #include "content/common/content_export.h" #include "ipc/ipc_message.h" @@ -60,12 +62,16 @@ DropData(const DropData& other); ~DropData(); + // Returns a sanitized filename to use for the dragged image, or base::nullopt + // if no sanitized name could be synthesized. + base::Optional<base::FilePath> GetSafeFilenameForImageFileContents() const; + int view_id = MSG_ROUTING_NONE; // Whether this drag originated from a renderer. bool did_originate_from_renderer; - // User is dragging a link into the webview. + // User is dragging a link or image. GURL url; base::string16 url_title; // The title associated with |url|. @@ -98,9 +104,11 @@ base::NullableString16 html; GURL html_base_url; - // User is dragging data from the webview (e.g., an image). - base::string16 file_description_filename; + // User is dragging an image out of the WebView. std::string file_contents; + GURL file_contents_source_url; + base::FilePath::StringType file_contents_filename_extension; + std::string file_contents_content_disposition; std::map<base::string16, base::string16> custom_data;
diff --git a/content/public/common/media_metadata.cc b/content/public/common/media_metadata.cc index 32b353a5..5a34d74 100644 --- a/content/public/common/media_metadata.cc +++ b/content/public/common/media_metadata.cc
@@ -9,6 +9,17 @@ namespace content { +MediaMetadata::MediaImage::MediaImage() = default; + +MediaMetadata::MediaImage::MediaImage(const MediaImage& other) = default; + +MediaMetadata::MediaImage::~MediaImage() = default; + +bool MediaMetadata::MediaImage::operator==( + const MediaMetadata::MediaImage& other) const { + return src == other.src && type == other.type && sizes == other.sizes; +} + MediaMetadata::MediaMetadata() = default; MediaMetadata::~MediaMetadata() = default;
diff --git a/content/public/common/media_metadata.h b/content/public/common/media_metadata.h index baec2c7..30a8682 100644 --- a/content/public/common/media_metadata.h +++ b/content/public/common/media_metadata.h
@@ -9,16 +9,37 @@ #include "base/strings/string16.h" #include "content/common/content_export.h" -#include "content/public/common/manifest.h" +#include "ui/gfx/geometry/size.h" +#include "url/gurl.h" namespace content { // The MediaMetadata is a structure carrying information associated to a // content::MediaSession. struct CONTENT_EXPORT MediaMetadata { - // TODO(zqzhang): move |Manifest::Icon| to a common place. See - // https://crbug.com/621859. - using MediaImage = Manifest::Icon; + // Structure representing an MediaImage as per the MediaSession API, see: + // https://wicg.github.io/mediasession/#dictdef-mediaimage + struct CONTENT_EXPORT MediaImage { + MediaImage(); + MediaImage(const MediaImage& other); + ~MediaImage(); + + bool operator==(const MediaImage& other) const; + + // MUST be a valid url. If an icon doesn't have a valid URL, it will not be + // successfully parsed, thus will not be represented in the Manifest. + GURL src; + + // Empty if the parsing failed or the field was not present. The type can be + // any string and doesn't have to be a valid image MIME type at this point. + // It is up to the consumer of the object to check if the type matches a + // supported type. + base::string16 type; + + // Empty if the parsing failed, the field was not present or empty. + // The special value "any" is represented by gfx::Size(0, 0). + std::vector<gfx::Size> sizes; + }; MediaMetadata(); ~MediaMetadata();
diff --git a/content/public/common/url_constants.cc b/content/public/common/url_constants.cc index 6064c2c6..bd9d6147 100644 --- a/content/public/common/url_constants.cc +++ b/content/public/common/url_constants.cc
@@ -16,6 +16,9 @@ #if defined(OS_CHROMEOS) const char kExternalFileScheme[] = "externalfile"; #endif +#if defined(OS_ANDROID) +const char kChromeNativeUIScheme[] = "chrome-native"; +#endif const char kAboutSrcDocURL[] = "about:srcdoc"; @@ -28,6 +31,9 @@ const char kChromeUIGpuHost[] = "gpu"; const char kChromeUIHistogramHost[] = "histograms"; const char kChromeUIHistoryHost[] = "history"; +#if defined(OS_ANDROID) +const char kChromeUIHistoryFrameHost[] = "history-frame"; +#endif const char kChromeUIMediaInternalsHost[] = "media-internals"; const char kChromeUIMemoryExhaustHost[] = "memory-exhaust"; const char kChromeUINetworkViewCacheHost[] = "view-http-cache"; @@ -67,4 +73,9 @@ const char kChromeUIResourcesURL[] = "chrome://resources/"; const char kChromeUIShorthangURL[] = "chrome://shorthang/"; +#if defined(OS_ANDROID) +const char kChromeUIHistoryURL[] = "chrome://history/"; +const char kChromeUINativeHistoryURL[] = "chrome-native://history/"; +#endif + } // namespace content
diff --git a/content/public/common/url_constants.h b/content/public/common/url_constants.h index f518a6e..cda43044 100644 --- a/content/public/common/url_constants.h +++ b/content/public/common/url_constants.h
@@ -23,6 +23,9 @@ #if defined(OS_CHROMEOS) CONTENT_EXPORT extern const char kExternalFileScheme[]; #endif +#if defined(OS_ANDROID) +CONTENT_EXPORT extern const char kChromeNativeUIScheme[]; +#endif // Hosts for about URLs. CONTENT_EXPORT extern const char kAboutSrcDocURL[]; @@ -35,6 +38,9 @@ CONTENT_EXPORT extern const char kChromeUIGpuHost[]; CONTENT_EXPORT extern const char kChromeUIHistogramHost[]; CONTENT_EXPORT extern const char kChromeUIHistoryHost[]; +#if defined(OS_ANDROID) +CONTENT_EXPORT extern const char kChromeUIHistoryFrameHost[]; +#endif CONTENT_EXPORT extern const char kChromeUIIndexedDBInternalsHost[]; CONTENT_EXPORT extern const char kChromeUIMediaInternalsHost[]; CONTENT_EXPORT extern const char kChromeUIMemoryExhaustHost[]; @@ -75,6 +81,10 @@ CONTENT_EXPORT extern const char kChromeUINetworkViewCacheURL[]; CONTENT_EXPORT extern const char kChromeUIResourcesURL[]; CONTENT_EXPORT extern const char kChromeUIShorthangURL[]; +#if defined(OS_ANDROID) +CONTENT_EXPORT extern const char kChromeUIHistoryURL[]; +CONTENT_EXPORT extern const char kChromeUINativeHistoryURL[]; +#endif } // namespace content
diff --git a/content/public/renderer/render_frame_observer.h b/content/public/renderer/render_frame_observer.h index 0c8dfed..7211fdc 100644 --- a/content/public/renderer/render_frame_observer.h +++ b/content/public/renderer/render_frame_observer.h
@@ -19,6 +19,7 @@ #include "v8/include/v8.h" namespace blink { +class WebDataSource; class WebFormElement; class WebNode; class WebString; @@ -62,7 +63,7 @@ virtual void WillCommitProvisionalLoad() {} virtual void DidCommitProvisionalLoad(bool is_new_navigation, bool is_same_page_navigation) {} - virtual void DidStartProvisionalLoad() {} + virtual void DidStartProvisionalLoad(blink::WebDataSource* data_source) {} virtual void DidFailProvisionalLoad(const blink::WebURLError& error) {} virtual void DidFinishLoad() {} virtual void DidFinishDocumentLoad() {}
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/TestInputMethodManagerWrapper.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/TestInputMethodManagerWrapper.java index 68452ed..932370b 100644 --- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/TestInputMethodManagerWrapper.java +++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/TestInputMethodManagerWrapper.java
@@ -90,15 +90,20 @@ candidatesEnd); Pair<Range, Range> newUpdateSelection = new Pair<>(new Range(selStart, selEnd), new Range(candidatesStart, candidatesEnd)); + Range lastSelection = null; + Range lastComposition = null; if (!mUpdateSelectionList.isEmpty()) { Pair<Range, Range> lastUpdateSelection = mUpdateSelectionList.get(mUpdateSelectionList.size() - 1); if (lastUpdateSelection.equals(newUpdateSelection)) return; + lastSelection = lastUpdateSelection.first; + lastComposition = lastUpdateSelection.second; } mUpdateSelectionList.add(new Pair<Range, Range>( new Range(selStart, selEnd), new Range(candidatesStart, candidatesEnd))); mSelection.set(selStart, selEnd); mComposition.set(candidatesStart, candidatesEnd); + onUpdateSelection(lastSelection, lastComposition, mSelection, mComposition); } @Override @@ -162,4 +167,8 @@ public CursorAnchorInfo getLastCursorAnchorInfo() { return mLastCursorAnchorInfo; } + + public void onUpdateSelection(Range oldSel, Range oldComp, Range newSel, Range newComp) {} + + public void expectsSelectionOutsideComposition() {} }
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn index 992e8a9f..7ecd0bec 100644 --- a/content/renderer/BUILD.gn +++ b/content/renderer/BUILD.gn
@@ -535,10 +535,12 @@ "media/aec_dump_message_filter.h", "media/audio_repetition_detector.cc", "media/audio_repetition_detector.h", - "media/audio_track_recorder.cc", - "media/audio_track_recorder.h", - "media/canvas_capture_handler.cc", - "media/canvas_capture_handler.h", + "media/capturefromelement/canvas_capture_handler.cc", + "media/capturefromelement/canvas_capture_handler.h", + "media/capturefromelement/html_audio_element_capturer_source.cc", + "media/capturefromelement/html_audio_element_capturer_source.h", + "media/capturefromelement/html_video_element_capturer_source.cc", + "media/capturefromelement/html_video_element_capturer_source.h", "media/external_media_stream_audio_source.cc", "media/external_media_stream_audio_source.h", "media/gpu/rtc_video_decoder.cc", @@ -549,10 +551,6 @@ "media/gpu/rtc_video_encoder.h", "media/gpu/rtc_video_encoder_factory.cc", "media/gpu/rtc_video_encoder_factory.h", - "media/html_audio_element_capturer_source.cc", - "media/html_audio_element_capturer_source.h", - "media/html_video_element_capturer_source.cc", - "media/html_video_element_capturer_source.h", "media/image_capture_frame_grabber.cc", "media/image_capture_frame_grabber.h", "media/local_media_stream_audio_source.cc", @@ -561,8 +559,6 @@ "media/media_devices_event_dispatcher.h", "media/media_devices_listener_impl.cc", "media/media_devices_listener_impl.h", - "media/media_recorder_handler.cc", - "media/media_recorder_handler.h", "media/media_stream.cc", "media/media_stream.h", "media/media_stream_audio_deliverer.h", @@ -580,6 +576,8 @@ "media/media_stream_center.h", "media/media_stream_constraints_util.cc", "media/media_stream_constraints_util.h", + "media/media_stream_constraints_util_video_source.cc", + "media/media_stream_constraints_util_video_source.h", "media/media_stream_dispatcher.cc", "media/media_stream_dispatcher.h", "media/media_stream_dispatcher_eventhandler.h", @@ -600,6 +598,12 @@ "media/media_stream_video_track.h", "media/peer_connection_tracker.cc", "media/peer_connection_tracker.h", + "media/recorder/audio_track_recorder.cc", + "media/recorder/audio_track_recorder.h", + "media/recorder/media_recorder_handler.cc", + "media/recorder/media_recorder_handler.h", + "media/recorder/video_track_recorder.cc", + "media/recorder/video_track_recorder.h", "media/remote_media_stream_impl.cc", "media/remote_media_stream_impl.h", "media/rtc_certificate.cc", @@ -621,8 +625,6 @@ "media/user_media_client_impl.h", "media/video_track_adapter.cc", "media/video_track_adapter.h", - "media/video_track_recorder.cc", - "media/video_track_recorder.h", "media/webaudio_media_stream_source.cc", "media/webaudio_media_stream_source.h", "media/webrtc/media_stream_remote_video_source.cc",
diff --git a/content/renderer/drop_data_builder.cc b/content/renderer/drop_data_builder.cc index 65a5dc5f..4b3875b2 100644 --- a/content/renderer/drop_data_builder.cc +++ b/content/renderer/drop_data_builder.cc
@@ -58,7 +58,16 @@ case WebDragData::Item::StorageTypeBinaryData: result.file_contents.assign(item.binaryData.data(), item.binaryData.size()); - result.file_description_filename = item.title.utf16(); + result.file_contents_source_url = item.binaryDataSourceURL; +#if defined(OS_WIN) + result.file_contents_filename_extension = + item.binaryDataFilenameExtension.utf16(); +#else + result.file_contents_filename_extension = + item.binaryDataFilenameExtension.utf8(); +#endif + result.file_contents_content_disposition = + item.binaryDataContentDisposition.utf8(); break; case WebDragData::Item::StorageTypeFilename: // TODO(varunjain): This only works on chromeos. Support win/mac/gtk.
diff --git a/content/renderer/media/capturefromelement/OWNERS b/content/renderer/media/capturefromelement/OWNERS new file mode 100644 index 0000000..446f8fb0 --- /dev/null +++ b/content/renderer/media/capturefromelement/OWNERS
@@ -0,0 +1,4 @@ +emircan@chromium.org +mcasas@chromium.org + +# COMPONENT: Blink>MediaStream>CaptureFromElement
diff --git a/content/renderer/media/canvas_capture_handler.cc b/content/renderer/media/capturefromelement/canvas_capture_handler.cc similarity index 98% rename from content/renderer/media/canvas_capture_handler.cc rename to content/renderer/media/capturefromelement/canvas_capture_handler.cc index fef1dc6f..b462e73 100644 --- a/content/renderer/media/canvas_capture_handler.cc +++ b/content/renderer/media/capturefromelement/canvas_capture_handler.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/renderer/media/canvas_capture_handler.h" +#include "content/renderer/media/capturefromelement/canvas_capture_handler.h" #include <utility>
diff --git a/content/renderer/media/canvas_capture_handler.h b/content/renderer/media/capturefromelement/canvas_capture_handler.h similarity index 94% rename from content/renderer/media/canvas_capture_handler.h rename to content/renderer/media/capturefromelement/canvas_capture_handler.h index 7c2a523e..9a0cb4b 100644 --- a/content/renderer/media/canvas_capture_handler.h +++ b/content/renderer/media/capturefromelement/canvas_capture_handler.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_RENDERER_MEDIA_CANVAS_CAPTURE_HANDLER_H_ -#define CONTENT_RENDERER_MEDIA_CANVAS_CAPTURE_HANDLER_H_ +#ifndef CONTENT_RENDERER_MEDIA_CAPTUREFROMELEMENT_CANVAS_CAPTURE_HANDLER_H_ +#define CONTENT_RENDERER_MEDIA_CAPTUREFROMELEMENT_CANVAS_CAPTURE_HANDLER_H_ #include <stddef.h> #include <stdint.h> @@ -106,4 +106,4 @@ } // namespace content -#endif // CONTENT_RENDERER_MEDIA_CANVAS_CAPTURE_HANDLER_H_ +#endif // CONTENT_RENDERER_MEDIA_CAPTUREFROMELEMENT_CANVAS_CAPTURE_HANDLER_H_
diff --git a/content/renderer/media/canvas_capture_handler_unittest.cc b/content/renderer/media/capturefromelement/canvas_capture_handler_unittest.cc similarity index 98% rename from content/renderer/media/canvas_capture_handler_unittest.cc rename to content/renderer/media/capturefromelement/canvas_capture_handler_unittest.cc index 0a7c6caa..5a592893 100644 --- a/content/renderer/media/canvas_capture_handler_unittest.cc +++ b/content/renderer/media/capturefromelement/canvas_capture_handler_unittest.cc
@@ -7,7 +7,7 @@ #include "base/run_loop.h" #include "base/threading/thread_task_runner_handle.h" #include "content/child/child_process.h" -#include "content/renderer/media/canvas_capture_handler.h" +#include "content/renderer/media/capturefromelement/canvas_capture_handler.h" #include "content/renderer/media/media_stream_video_capturer_source.h" #include "media/base/limits.h" #include "testing/gmock/include/gmock/gmock.h"
diff --git a/content/renderer/media/html_audio_element_capturer_source.cc b/content/renderer/media/capturefromelement/html_audio_element_capturer_source.cc similarity index 96% rename from content/renderer/media/html_audio_element_capturer_source.cc rename to content/renderer/media/capturefromelement/html_audio_element_capturer_source.cc index 7e0edfc9..ea23efdd 100644 --- a/content/renderer/media/html_audio_element_capturer_source.cc +++ b/content/renderer/media/capturefromelement/html_audio_element_capturer_source.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/renderer/media/html_audio_element_capturer_source.h" +#include "content/renderer/media/capturefromelement/html_audio_element_capturer_source.h" #include "base/threading/thread_task_runner_handle.h" #include "media/base/audio_parameters.h"
diff --git a/content/renderer/media/html_audio_element_capturer_source.h b/content/renderer/media/capturefromelement/html_audio_element_capturer_source.h similarity index 86% rename from content/renderer/media/html_audio_element_capturer_source.h rename to content/renderer/media/capturefromelement/html_audio_element_capturer_source.h index 48ea500..9fe33c6 100644 --- a/content/renderer/media/html_audio_element_capturer_source.h +++ b/content/renderer/media/capturefromelement/html_audio_element_capturer_source.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_RENDERER_MEDIA_HTML_AUDIO_ELEMENT_CAPTURER_SOURCE_H_ -#define CONTENT_RENDERER_MEDIA_HTML_AUDIO_ELEMENT_CAPTURER_SOURCE_H_ +#ifndef CONTENT_RENDERER_MEDIA_CAPTUREFROMELEMENT_HTML_AUDIO_ELEMENT_CAPTURER_SOURCE_H_ +#define CONTENT_RENDERER_MEDIA_CAPTUREFROMELEMENT_HTML_AUDIO_ELEMENT_CAPTURER_SOURCE_H_ #include "base/callback.h" #include "base/memory/weak_ptr.h" @@ -60,4 +60,4 @@ } // namespace content -#endif // CONTENT_RENDERER_MEDIA_HTML_AUDIO_ELEMENT_CAPTURER_SOURCE_H_ +#endif // CONTENT_RENDERER_MEDIA_CAPTUREFROMELEMENT_HTML_AUDIO_ELEMENT_CAPTURER_SOURCE_H_
diff --git a/content/renderer/media/html_audio_element_capturer_source_unittest.cc b/content/renderer/media/capturefromelement/html_audio_element_capturer_source_unittest.cc similarity index 98% rename from content/renderer/media/html_audio_element_capturer_source_unittest.cc rename to content/renderer/media/capturefromelement/html_audio_element_capturer_source_unittest.cc index 5e60e03..0ef426f 100644 --- a/content/renderer/media/html_audio_element_capturer_source_unittest.cc +++ b/content/renderer/media/capturefromelement/html_audio_element_capturer_source_unittest.cc
@@ -6,7 +6,7 @@ #include "base/run_loop.h" #include "base/threading/thread_task_runner_handle.h" #include "content/public/renderer/media_stream_audio_sink.h" -#include "content/renderer/media/html_audio_element_capturer_source.h" +#include "content/renderer/media/capturefromelement/html_audio_element_capturer_source.h" #include "content/renderer/media/media_stream_audio_track.h" #include "media/audio/null_audio_sink.h" #include "media/base/audio_parameters.h"
diff --git a/content/renderer/media/html_video_element_capturer_source.cc b/content/renderer/media/capturefromelement/html_video_element_capturer_source.cc similarity index 98% rename from content/renderer/media/html_video_element_capturer_source.cc rename to content/renderer/media/capturefromelement/html_video_element_capturer_source.cc index b9230f4..78bbdc2 100644 --- a/content/renderer/media/html_video_element_capturer_source.cc +++ b/content/renderer/media/capturefromelement/html_video_element_capturer_source.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/renderer/media/html_video_element_capturer_source.h" +#include "content/renderer/media/capturefromelement/html_video_element_capturer_source.h" #include "base/location.h" #include "base/memory/ptr_util.h"
diff --git a/content/renderer/media/html_video_element_capturer_source.h b/content/renderer/media/capturefromelement/html_video_element_capturer_source.h similarity index 91% rename from content/renderer/media/html_video_element_capturer_source.h rename to content/renderer/media/capturefromelement/html_video_element_capturer_source.h index 295ecdc..e13c42e 100644 --- a/content/renderer/media/html_video_element_capturer_source.h +++ b/content/renderer/media/capturefromelement/html_video_element_capturer_source.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_RENDERER_MEDIA_HTML_VIDEO_ELEMENT_CAPTURER_SOURCE_H_ -#define CONTENT_RENDERER_MEDIA_HTML_VIDEO_ELEMENT_CAPTURER_SOURCE_H_ +#ifndef CONTENT_RENDERER_MEDIA_CAPTUREFROMELEMENT_HTML_VIDEO_ELEMENT_CAPTURER_SOURCE_H_ +#define CONTENT_RENDERER_MEDIA_CAPTUREFROMELEMENT_HTML_VIDEO_ELEMENT_CAPTURER_SOURCE_H_ #include "base/callback.h" #include "base/memory/weak_ptr.h" @@ -84,4 +84,4 @@ } // namespace content -#endif // CONTENT_RENDERER_MEDIA_HTML_VIDEO_ELEMENT_CAPTURER_SOURCE_H_ +#endif // CONTENT_RENDERER_MEDIA_CAPTUREFROMELEMENT_HTML_VIDEO_ELEMENT_CAPTURER_SOURCE_H_
diff --git a/content/renderer/media/html_video_element_capturer_source_unittest.cc b/content/renderer/media/capturefromelement/html_video_element_capturer_source_unittest.cc similarity index 98% rename from content/renderer/media/html_video_element_capturer_source_unittest.cc rename to content/renderer/media/capturefromelement/html_video_element_capturer_source_unittest.cc index 025c7ff..b5d1abc 100644 --- a/content/renderer/media/html_video_element_capturer_source_unittest.cc +++ b/content/renderer/media/capturefromelement/html_video_element_capturer_source_unittest.cc
@@ -6,7 +6,7 @@ #include "base/memory/weak_ptr.h" #include "base/run_loop.h" #include "base/threading/thread_task_runner_handle.h" -#include "content/renderer/media/html_video_element_capturer_source.h" +#include "content/renderer/media/capturefromelement/html_video_element_capturer_source.h" #include "media/base/limits.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/content/renderer/media/media_stream_constraints_util_video_source.cc b/content/renderer/media/media_stream_constraints_util_video_source.cc new file mode 100644 index 0000000..48a105c --- /dev/null +++ b/content/renderer/media/media_stream_constraints_util_video_source.cc
@@ -0,0 +1,732 @@ +// 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 "content/renderer/media/media_stream_constraints_util_video_source.h" + +#include <algorithm> +#include <cmath> +#include <limits> +#include <utility> +#include <vector> + +#include "content/renderer/media/media_stream_video_source.h" +#include "third_party/WebKit/public/platform/WebMediaConstraints.h" +#include "third_party/WebKit/public/platform/WebString.h" + +namespace content { + +namespace { + +// Number of default settings to be used as final tie-breaking criteria for +// settings that are equally good at satisfying constraints: +// device ID, power-line frequency, resolution and frame rate. +const int kNumDefaultDistanceEntries = 4; + +// The default resolution to be preferred as tie-breaking criterion. +const int kDefaultResolutionArea = MediaStreamVideoSource::kDefaultWidth * + MediaStreamVideoSource::kDefaultHeight; + +// The minimum aspect ratio to be supported by sources. +const double kMinSourceAspectRatio = 0.05; + +blink::WebString ToWebString(::mojom::FacingMode facing_mode) { + switch (facing_mode) { + case ::mojom::FacingMode::USER: + return blink::WebString::fromASCII("user"); + case ::mojom::FacingMode::ENVIRONMENT: + return blink::WebString::fromASCII("environment"); + case ::mojom::FacingMode::LEFT: + return blink::WebString::fromASCII("left"); + case ::mojom::FacingMode::RIGHT: + return blink::WebString::fromASCII("right"); + default: + return blink::WebString::fromASCII(""); + } +} + +template <typename ConstraintType> +bool ConstraintHasMax(const ConstraintType& constraint) { + return constraint.hasMax() || constraint.hasExact(); +} + +template <typename ConstraintType> +bool ConstraintHasMin(const ConstraintType& constraint) { + return constraint.hasMin() || constraint.hasExact(); +} + +template <typename ConstraintType> +auto ConstraintMax(const ConstraintType& constraint) + -> decltype(constraint.max()) { + DCHECK(ConstraintHasMax(constraint)); + return constraint.hasExact() ? constraint.exact() : constraint.max(); +} + +template <typename ConstraintType> +auto ConstraintMin(const ConstraintType& constraint) + -> decltype(constraint.min()) { + DCHECK(ConstraintHasMin(constraint)); + return constraint.hasExact() ? constraint.exact() : constraint.min(); +} + +// Generic distance function between two numeric values. Based on the fitness +// distance function described in +// https://w3c.github.io/mediacapture-main/#dfn-fitness-distance +double Distance(double value1, double value2) { + if (std::fabs(value1 - value2) <= blink::DoubleConstraint::kConstraintEpsilon) + return 0.0; + + return std::fabs(value1 - value2) / + std::max(std::fabs(value1), std::fabs(value2)); +} + +// Returns a pair with the minimum and maximum aspect ratios supported by the +// source resolution settings |source_height| and |source_width|, subject to +// given width and height constraints. +void GetSourceAspectRatioRange(int source_height, + int source_width, + const blink::LongConstraint& height_constraint, + const blink::LongConstraint& width_constraint, + double* min_source_aspect_ratio, + double* max_source_aspect_ratio) { + DCHECK_GE(source_height, 1); + DCHECK_GE(source_width, 1); + long min_height = 1; + if (ConstraintHasMin(height_constraint)) + min_height = std::max(min_height, ConstraintMin(height_constraint)); + + long max_height = source_height; + if (ConstraintHasMax(height_constraint)) + max_height = std::min(max_height, ConstraintMax(height_constraint)); + + long min_width = 1; + if (ConstraintHasMin(width_constraint)) + min_width = std::max(min_width, ConstraintMin(width_constraint)); + + long max_width = source_width; + if (ConstraintHasMax(width_constraint)) + max_width = std::min(max_width, ConstraintMax(width_constraint)); + + *min_source_aspect_ratio = + std::max(static_cast<double>(min_width) / static_cast<double>(max_height), + kMinSourceAspectRatio); + *max_source_aspect_ratio = + std::max(static_cast<double>(max_width) / static_cast<double>(min_height), + kMinSourceAspectRatio); +} + +// Returns a custom distance between a string and a string constraint. +// Returns 0 if |value| satisfies |constraint|. HUGE_VAL otherwise. +double StringConstraintSourceDistance(const blink::WebString& value, + const blink::StringConstraint& constraint, + const char** failed_constraint_name) { + if (constraint.matches(value)) + return 0.0; + + if (failed_constraint_name) + *failed_constraint_name = constraint.name(); + return HUGE_VAL; +} + +// Returns a custom distance function suitable for screen dimensions, given +// a |constraint| (e.g. width or height) and a candidate value |source_value|. +// A source can support track resolutions in the range [1, |source_value|], +// using cropping if necessary. +// If the source range and the constraint range are disjoint, return HUGE_VAL. +// If the constraint has maximum, penalize sources that exceed the maximum +// by returning Distance(|source_value|, maximum). This is intended to prefer, +// among sources that satisfy the constraint, those that have lower resource +// usage. Otherwise, return zero. +double ResolutionConstraintSourceDistance( + int source_value, + const blink::LongConstraint& constraint, + const char** failed_constraint_name) { + DCHECK_GE(source_value, 1); + bool constraint_has_max = ConstraintHasMax(constraint); + long constraint_max = constraint_has_max ? ConstraintMax(constraint) : -1; + + // If the intersection between the source range and the constraint range is + // empty, return HUGE_VAL. + if ((constraint_has_max && constraint_max < 1) || + (ConstraintHasMin(constraint) && + source_value < ConstraintMin(constraint))) { + if (failed_constraint_name) + *failed_constraint_name = constraint.name(); + return HUGE_VAL; + } + + // If the source value exceeds the maximum requested, penalize. + if (constraint_has_max && source_value > constraint_max) + return Distance(source_value, constraint_max); + + return 0.0; +} + +// Returns a custom distance function suitable for frame rate, given +// a |constraint| and a candidate value. +// A source can support track frame rates in the interval (0.0, |source_value|], +// using frame-rate adjustments if necessary. +// If the source range and the constraint range are disjoint, return HUGE_VAL. +// If the constraint has maximum, penalize source frame rates that exceed the +// maximum by returning Distance(|source_value|, maximum). This is intended to +// prefer, among sources that satisfy the constraint, those that have lower +// resource usage. Otherwise, return zero. +double FrameRateConstraintSourceDistance( + double source_value, + const blink::DoubleConstraint& constraint, + const char** failed_constraint_name) { + DCHECK_GT(source_value, 0.0); + bool constraint_has_max = ConstraintHasMax(constraint); + double constraint_max = constraint_has_max ? ConstraintMax(constraint) : -1.0; + + if ((constraint_has_max && constraint_max <= 0.0) || + (ConstraintHasMin(constraint) && + source_value < ConstraintMin(constraint) - + blink::DoubleConstraint::kConstraintEpsilon)) { + if (failed_constraint_name) + *failed_constraint_name = constraint.name(); + return HUGE_VAL; + } + + if (constraint_has_max && source_value > constraint_max) + return Distance(source_value, constraint_max); + + return 0.0; +} + +// Returns a custom distance function suitable for aspect ratio, given +// the values for the aspect_ratio, width and height constraints, and candidate +// source values for width and height. +// A source can support track resolutions that range from +// min_width x min_height to max_width x max_height +// where +// min_width = max(1, width_constraint.min) +// min_height = max(1, height_constraint.min) +// max_width = min(source_width, width_constraint.max) +// max_height = min(source_height, height_constraint.max) +// The aspect-ratio range supported by the source is determined by the extremes +// of those resolutions. +// min_ar = min_width / max_height. +// max_ar = max_width / min_height. +// +// If the supported range [min_ar, max_ar] and the range specified by the +// aspectRatio constraint are disjoint, return HUGE_VAL. Otherwise, return zero. +double AspectRatioConstraintSourceDistance( + int source_height, + int source_width, + const blink::LongConstraint& height_constraint, + const blink::LongConstraint& width_constraint, + const blink::DoubleConstraint& aspect_ratio_constraint, + const char** failed_constraint_name) { + DCHECK_GT(source_height, 1); + DCHECK_GT(source_width, 1); + + bool ar_constraint_has_min = ConstraintHasMin(aspect_ratio_constraint); + double ar_constraint_min = + ar_constraint_has_min ? ConstraintMin(aspect_ratio_constraint) : -1.0; + bool ar_constraint_has_max = ConstraintHasMax(aspect_ratio_constraint); + double ar_constraint_max = + ar_constraint_has_max ? ConstraintMax(aspect_ratio_constraint) : -1.0; + + double min_source_aspect_ratio; + double max_source_aspect_ratio; + GetSourceAspectRatioRange(source_height, source_width, height_constraint, + width_constraint, &min_source_aspect_ratio, + &max_source_aspect_ratio); + + // If the supported range and the constraint rage are disjoint, return + // HUGE_VAL. + if ((ar_constraint_has_min && + max_source_aspect_ratio < + ar_constraint_min - blink::DoubleConstraint::kConstraintEpsilon) || + (ar_constraint_has_max && + min_source_aspect_ratio > + ar_constraint_max + blink::DoubleConstraint::kConstraintEpsilon)) { + if (failed_constraint_name) + *failed_constraint_name = aspect_ratio_constraint.name(); + return HUGE_VAL; + } + + return 0.0; +} + +// Returns a custom distance function suitable for the googPowerLineFrequency +// constraint, given a |constraint| and a candidate value |source_value|. +// The distance is HUGE_VAL if |source_value| cannot satisfy |constraint|. +// Otherwise, the distance is zero. +double PowerLineFrequencyConstraintSourceDistance( + const blink::LongConstraint& constraint, + media::PowerLineFrequency source_value, + const char** failed_constraint_name) { + bool constraint_has_min = ConstraintHasMin(constraint); + bool constraint_has_max = ConstraintHasMax(constraint); + long constraint_min = constraint_has_min ? ConstraintMin(constraint) : -1L; + long constraint_max = constraint_has_max ? ConstraintMax(constraint) : -1L; + long source_value_long = static_cast<long>(source_value); + + if ((constraint_has_max && source_value_long > constraint_max) || + (constraint_has_min && source_value_long < constraint_min)) { + if (failed_constraint_name) + *failed_constraint_name = constraint.name(); + return HUGE_VAL; + } + + return 0.0; +} + +// Returns a custom distance for constraints that depend on the device +// characteristics that have a fixed value. +double DeviceSourceDistance( + const std::string& device_id, + ::mojom::FacingMode facing_mode, + const blink::WebMediaTrackConstraintSet& constraint_set, + const char** failed_constraint_name) { + return StringConstraintSourceDistance(blink::WebString::fromASCII(device_id), + constraint_set.deviceId, + failed_constraint_name) + + StringConstraintSourceDistance(ToWebString(facing_mode), + constraint_set.facingMode, + failed_constraint_name); +} + +// Returns a custom distance for constraints that depend on a video-capture +// format. +double FormatSourceDistance( + const media::VideoCaptureFormat& format, + const blink::WebMediaTrackConstraintSet& constraint_set, + const char** failed_constraint_name) { + return ResolutionConstraintSourceDistance(format.frame_size.height(), + constraint_set.height, + failed_constraint_name) + + ResolutionConstraintSourceDistance(format.frame_size.width(), + constraint_set.width, + failed_constraint_name) + + AspectRatioConstraintSourceDistance( + format.frame_size.height(), format.frame_size.width(), + constraint_set.height, constraint_set.width, + constraint_set.aspectRatio, failed_constraint_name) + + FrameRateConstraintSourceDistance(format.frame_rate, + constraint_set.frameRate, + failed_constraint_name); +} + +// Returns a custom distance between a set of candidate settings and a +// constraint set. It is simply the sum of the distances for each individual +// setting in |candidate|. +// If |candidate| cannot satisfy constraint, the distance is HUGE_VAL. +// Otherwise the distance is a finite value. Candidates with lower distance +// satisfy |constraint_set| in a "better" way. +double CandidateSourceDistance( + const VideoCaptureSourceSettings& candidate, + const blink::WebMediaTrackConstraintSet& constraint_set, + const char** failed_constraint_name) { + return DeviceSourceDistance(candidate.device_id(), candidate.facing_mode(), + constraint_set, failed_constraint_name) + + FormatSourceDistance(candidate.format(), constraint_set, + failed_constraint_name) + + PowerLineFrequencyConstraintSourceDistance( + constraint_set.googPowerLineFrequency, + candidate.power_line_frequency(), failed_constraint_name); +} + +// Returns the fitness distance between |value| and |constraint|. +// Based on https://w3c.github.io/mediacapture-main/#dfn-fitness-distance. +double StringConstraintFitnessDistance( + const blink::WebString& value, + const blink::StringConstraint& constraint) { + if (!constraint.hasIdeal()) + return 0.0; + + for (auto& ideal_value : constraint.ideal()) { + if (value == ideal_value) + return 0.0; + } + + return 1.0; +} + +// Returns the fitness distance between |value| and |constraint| for +// resolution constraints (i.e., width and height). +// Based on https://w3c.github.io/mediacapture-main/#dfn-fitness-distance. +double ResolutionConstraintFitnessDistance( + long value, + const blink::LongConstraint& constraint) { + if (!constraint.hasIdeal()) + return 0.0; + + // Source resolutions greater than ideal support the ideal value with + // cropping. + if (value >= constraint.ideal()) + return 0.0; + + return Distance(value, constraint.ideal()); +} + +// Returns the fitness distance between |value| and |constraint| for +// resolution constraints (i.e., width and height), ignoring cropping. +// This measures how well a native resolution supports the idea value. +// Based on https://w3c.github.io/mediacapture-main/#dfn-fitness-distance. +double ResolutionConstraintNativeFitnessDistance( + long value, + const blink::LongConstraint& constraint) { + return constraint.hasIdeal() ? Distance(value, constraint.ideal()) : 0.0; +} + +// Returns the fitness distance between a source resolution settings +// and the aspectRatio constraint, taking into account resolution restrictions +// on the source imposed by the width and height constraints. +// Based on https://w3c.github.io/mediacapture-main/#dfn-fitness-distance. +double AspectRatioConstraintFitnessDistance( + long source_height, + long source_width, + const blink::LongConstraint& height_constraint, + const blink::LongConstraint& width_constraint, + const blink::DoubleConstraint& aspect_ratio_constraint) { + DCHECK_GT(source_height, 1); + DCHECK_GT(source_width, 1); + + if (!aspect_ratio_constraint.hasIdeal()) + return 0.0; + + double min_source_aspect_ratio; + double max_source_aspect_ratio; + GetSourceAspectRatioRange(source_height, source_width, height_constraint, + width_constraint, &min_source_aspect_ratio, + &max_source_aspect_ratio); + + // If the supported aspect ratio range does not include the ideal aspect + // ratio, compute fitness using the spec formula. + if (max_source_aspect_ratio < + aspect_ratio_constraint.ideal() - + blink::DoubleConstraint::kConstraintEpsilon) { + return Distance(max_source_aspect_ratio, aspect_ratio_constraint.ideal()); + } + + if (min_source_aspect_ratio > + aspect_ratio_constraint.ideal() + + blink::DoubleConstraint::kConstraintEpsilon) { + return Distance(min_source_aspect_ratio, aspect_ratio_constraint.ideal()); + } + + // Otherwise, the ideal aspect ratio can be supported and the fitness is 0. + return 0.0; +} + +// Returns the fitness distance between |value| and |constraint| for the +// frameRate constraint. +// Based on https://w3c.github.io/mediacapture-main/#dfn-fitness-distance. +double FrameRateConstraintFitnessDistance( + double value, + const blink::DoubleConstraint& constraint) { + if (!constraint.hasIdeal()) + return 0.0; + + // Source frame rates greater than ideal support the ideal value using + // frame-rate adjustment. + if (value >= + constraint.ideal() - blink::DoubleConstraint::kConstraintEpsilon) { + return 0.0; + } + + return Distance(value, constraint.ideal()); +} + +// Returns the fitness distance between |value| and |constraint| for the +// frameRate constraint, ignoring frame-rate adjustment. +// It measures how well the native frame rate supports the ideal value. +// Based on https://w3c.github.io/mediacapture-main/#dfn-fitness-distance. +double FrameRateConstraintNativeFitnessDistance( + double value, + const blink::DoubleConstraint& constraint) { + return constraint.hasIdeal() ? Distance(value, constraint.ideal()) : 0.0; +} + +// Returns the fitness distance between |value| and |constraint| for the +// googPowerLineFrequency constraint. +// Based on https://w3c.github.io/mediacapture-main/#dfn-fitness-distance. +double PowerLineFrequencyConstraintFitnessDistance( + long value, + const blink::LongConstraint& constraint) { + if (!constraint.hasIdeal()) + return 0.0; + + // This constraint is of type long, but it behaves as an enum. Thus, values + // equal to ideal have fitness 0.0 and any other values have fitness 1.0. + if (value == constraint.ideal()) + return 0.0; + + return 1.0; +} + +// Returns the fitness distance between a settings candidate and a constraint +// set. The returned value is the sum of the fitness distances between each +// setting in |candidate| and the corresponding constraint in |constraint_set|. +// Based on https://w3c.github.io/mediacapture-main/#dfn-fitness-distance. +double CandidateFitnessDistance( + const VideoCaptureSourceSettings& candidate, + const blink::WebMediaTrackConstraintSet& constraint_set) { + DCHECK(std::isfinite( + CandidateSourceDistance(candidate, constraint_set, nullptr))); + double fitness = 0.0; + fitness += AspectRatioConstraintFitnessDistance( + candidate.GetHeight(), candidate.GetWidth(), constraint_set.height, + constraint_set.width, constraint_set.aspectRatio); + fitness += StringConstraintFitnessDistance(candidate.GetDeviceId(), + constraint_set.deviceId); + fitness += StringConstraintFitnessDistance(candidate.GetFacingMode(), + constraint_set.facingMode); + fitness += FrameRateConstraintFitnessDistance(candidate.GetFrameRate(), + constraint_set.frameRate); + fitness += PowerLineFrequencyConstraintFitnessDistance( + candidate.GetPowerLineFrequency(), constraint_set.googPowerLineFrequency); + fitness += ResolutionConstraintFitnessDistance(candidate.GetHeight(), + constraint_set.height); + fitness += ResolutionConstraintFitnessDistance(candidate.GetWidth(), + constraint_set.width); + + return fitness; +} + +// Returns the native fitness distance between a settings candidate and a +// constraint set. The returned value is the sum of the fitness distances for +// the native values of settings that support a range of values (i.e., width, +// height and frame rate). +// Based on https://w3c.github.io/mediacapture-main/#dfn-fitness-distance. +double CandidateNativeFitnessDistance( + const VideoCaptureSourceSettings& candidate, + const blink::WebMediaTrackConstraintSet& constraint_set) { + DCHECK(std::isfinite( + CandidateSourceDistance(candidate, constraint_set, nullptr))); + double fitness = 0.0; + fitness += FrameRateConstraintNativeFitnessDistance(candidate.GetFrameRate(), + constraint_set.frameRate); + fitness += ResolutionConstraintNativeFitnessDistance(candidate.GetHeight(), + constraint_set.height); + fitness += ResolutionConstraintNativeFitnessDistance(candidate.GetWidth(), + constraint_set.width); + + return fitness; +} + +using DistanceVector = std::vector<double>; + +// This function appends additional entries to |distance_vector| based on +// custom distance metrics between |candidate| and some default settings. +// These entries are to be used as the final tie breaker for candidates that +// are equally good according to the spec and the custom distance functions +// between candidates and constraints. +void AppendDistanceFromDefault(const VideoCaptureSourceSettings& candidate, + const VideoCaptureCapabilities& capabilities, + DistanceVector* distance_vector) { + // Favor IDs that appear first in the enumeration. + for (size_t i = 0; i < capabilities.device_capabilities.size(); ++i) { + if (candidate.device_id() == + capabilities.device_capabilities[i]->device_id) { + distance_vector->push_back(i); + break; + } + } + + // Prefer default power-line frequency. + double power_line_frequency_distance = + candidate.power_line_frequency() == + media::PowerLineFrequency::FREQUENCY_DEFAULT + ? 0.0 + : HUGE_VAL; + distance_vector->push_back(power_line_frequency_distance); + + // Prefer a resolution with area close to the default. + int candidate_area = candidate.format().frame_size.GetArea(); + double resolution_distance = + candidate_area == kDefaultResolutionArea + ? 0.0 + : Distance(candidate_area, kDefaultResolutionArea); + distance_vector->push_back(resolution_distance); + + // Prefer a frame rate close to the default. + double frame_rate_distance = + candidate.format().frame_rate == MediaStreamVideoSource::kDefaultFrameRate + ? 0.0 + : Distance(candidate.format().frame_rate, + MediaStreamVideoSource::kDefaultFrameRate); + distance_vector->push_back(frame_rate_distance); +} + +} // namespace + +VideoCaptureCapabilities::VideoCaptureCapabilities() = default; +VideoCaptureCapabilities::VideoCaptureCapabilities( + VideoCaptureCapabilities&& other) = default; +VideoCaptureCapabilities::~VideoCaptureCapabilities() = default; +VideoCaptureCapabilities& VideoCaptureCapabilities::operator=( + VideoCaptureCapabilities&& other) = default; + +VideoCaptureSourceSettings::VideoCaptureSourceSettings( + const VideoCaptureSourceSettings& other) = default; +VideoCaptureSourceSettings::VideoCaptureSourceSettings( + VideoCaptureSourceSettings&& other) = default; +VideoCaptureSourceSettings::~VideoCaptureSourceSettings() = default; +VideoCaptureSourceSettings& VideoCaptureSourceSettings::operator=( + const VideoCaptureSourceSettings& other) = default; +VideoCaptureSourceSettings& VideoCaptureSourceSettings::operator=( + VideoCaptureSourceSettings&& other) = default; + +VideoCaptureSourceSettings::VideoCaptureSourceSettings() + : facing_mode_(::mojom::FacingMode::NONE), + power_line_frequency_(media::PowerLineFrequency::FREQUENCY_DEFAULT) {} + +VideoCaptureSourceSettings::VideoCaptureSourceSettings( + const std::string& device_id, + const media::VideoCaptureFormat& format, + ::mojom::FacingMode facing_mode, + media::PowerLineFrequency power_line_frequency) + : device_id_(device_id), + format_(format), + facing_mode_(facing_mode), + power_line_frequency_(power_line_frequency) {} + +blink::WebString VideoCaptureSourceSettings::GetFacingMode() const { + return ToWebString(facing_mode_); +} + +long VideoCaptureSourceSettings::GetPowerLineFrequency() const { + return static_cast<long>(power_line_frequency_); +} + +long VideoCaptureSourceSettings::GetWidth() const { + return format_.frame_size.width(); +} + +long VideoCaptureSourceSettings::GetHeight() const { + return format_.frame_size.height(); +} + +double VideoCaptureSourceSettings::GetFrameRate() const { + return format_.frame_rate; +} + +blink::WebString VideoCaptureSourceSettings::GetDeviceId() const { + return blink::WebString::fromASCII(device_id_.data()); +} + +const char kDefaultFailedConstraintName[] = ""; + +VideoCaptureSourceSelectionResult::VideoCaptureSourceSelectionResult() + : failed_constraint_name(kDefaultFailedConstraintName) {} +VideoCaptureSourceSelectionResult::VideoCaptureSourceSelectionResult( + const VideoCaptureSourceSelectionResult& other) = default; +VideoCaptureSourceSelectionResult::VideoCaptureSourceSelectionResult( + VideoCaptureSourceSelectionResult&& other) = default; +VideoCaptureSourceSelectionResult::~VideoCaptureSourceSelectionResult() = + default; +VideoCaptureSourceSelectionResult& VideoCaptureSourceSelectionResult::operator=( + const VideoCaptureSourceSelectionResult& other) = default; +VideoCaptureSourceSelectionResult& VideoCaptureSourceSelectionResult::operator=( + VideoCaptureSourceSelectionResult&& other) = default; + +VideoCaptureSourceSelectionResult SelectVideoCaptureSourceSettings( + const VideoCaptureCapabilities& capabilities, + const blink::WebMediaConstraints& constraints) { + // This function works only if infinity is defined for the double type. + DCHECK(std::numeric_limits<double>::has_infinity); + + // A distance vector contains: + // a) For each advanced constraint set, a 0/1 value indicating if the + // candidate satisfies the corresponding constraint set. + // b) Fitness distance for the candidate based on support for the ideal values + // of the basic constraint set. + // c) A custom distance value based on how "well" a candidate satisfies each + // constraint set, including basic and advanced sets. + // d) Native fitness distance for the candidate based on support for the + // ideal values of the basic constraint set using native values for + // settings that can support a range of values. + // e) A custom distance value based on how close the candidate is to default + // settings. + // Parts (a) and (b) are according to spec. Parts (c) to (e) are + // implementation specific and used to break ties. + DistanceVector best_distance(2 * constraints.advanced().size() + 3 + + kNumDefaultDistanceEntries); + std::fill(best_distance.begin(), best_distance.end(), HUGE_VAL); + VideoCaptureSourceSelectionResult result; + const char* failed_constraint_name = result.failed_constraint_name; + + for (auto& device : capabilities.device_capabilities) { + double basic_device_distance = + DeviceSourceDistance(device->device_id, device->facing_mode, + constraints.basic(), &failed_constraint_name); + if (!std::isfinite(basic_device_distance)) + continue; + + for (auto& format : device->formats) { + double basic_format_distance = FormatSourceDistance( + format, constraints.basic(), &failed_constraint_name); + if (!std::isfinite(basic_format_distance)) + continue; + + for (auto& power_line_frequency : capabilities.power_line_capabilities) { + double basic_power_line_frequency_distance = + PowerLineFrequencyConstraintSourceDistance( + constraints.basic().googPowerLineFrequency, + power_line_frequency, &failed_constraint_name); + if (!std::isfinite(basic_power_line_frequency_distance)) + continue; + + // The candidate satisfies the basic constraint set. + double candidate_basic_custom_distance = + basic_device_distance + basic_format_distance + + basic_power_line_frequency_distance; + DCHECK(std::isfinite(candidate_basic_custom_distance)); + + // Temporary vector to save custom distances for advanced constraints. + // Custom distances must be added to the candidate distance vector after + // all the spec-mandated values. + DistanceVector advanced_custom_distance_vector; + VideoCaptureSourceSettings candidate(device->device_id, format, + device->facing_mode, + power_line_frequency); + DistanceVector candidate_distance_vector; + // First criteria for valid candidates is satisfaction of advanced + // constraint sets. + for (const auto& advanced : constraints.advanced()) { + double custom_distance = + CandidateSourceDistance(candidate, advanced, nullptr); + advanced_custom_distance_vector.push_back(custom_distance); + double spec_distance = std::isfinite(custom_distance) ? 0 : 1; + candidate_distance_vector.push_back(spec_distance); + } + + // Second criterion is fitness distance. + candidate_distance_vector.push_back( + CandidateFitnessDistance(candidate, constraints.basic())); + + // Third criteria are custom distances to constraint sets. + candidate_distance_vector.push_back(candidate_basic_custom_distance); + std::copy(advanced_custom_distance_vector.begin(), + advanced_custom_distance_vector.end(), + std::back_inserter(candidate_distance_vector)); + + // Fourth criteria is native fitness distance. + candidate_distance_vector.push_back( + CandidateNativeFitnessDistance(candidate, constraints.basic())); + + // Final criteria are custom distances to default settings. + AppendDistanceFromDefault(candidate, capabilities, + &candidate_distance_vector); + + DCHECK_EQ(best_distance.size(), candidate_distance_vector.size()); + if (candidate_distance_vector < best_distance) { + best_distance = candidate_distance_vector; + result.settings = std::move(candidate); + result.failed_constraint_name = nullptr; + } + } + } + } + + if (!result.has_value()) + result.failed_constraint_name = failed_constraint_name; + + return result; +} + +} // namespace content
diff --git a/content/renderer/media/media_stream_constraints_util_video_source.h b/content/renderer/media/media_stream_constraints_util_video_source.h new file mode 100644 index 0000000..6ff14ed --- /dev/null +++ b/content/renderer/media/media_stream_constraints_util_video_source.h
@@ -0,0 +1,155 @@ +// 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 CONTENT_RENDERER_MEDIA_MEDIA_STREAM_CONSTRAINTS_UTIL_VIDEO_SOURCE_H_ +#define CONTENT_RENDERER_MEDIA_MEDIA_STREAM_CONSTRAINTS_UTIL_VIDEO_SOURCE_H_ + +#include <iosfwd> +#include <string> +#include <vector> + +#include "content/common/content_export.h" +#include "content/common/media/media_devices.mojom.h" +#include "media/capture/video_capture_types.h" + +namespace blink { +class WebString; +class WebMediaConstraints; +} + +namespace content { + +struct CONTENT_EXPORT VideoCaptureCapabilities { + VideoCaptureCapabilities(); + VideoCaptureCapabilities(VideoCaptureCapabilities&& other); + ~VideoCaptureCapabilities(); + VideoCaptureCapabilities& operator=(VideoCaptureCapabilities&& other); + + // Each field is independent of each other. + std::vector<::mojom::VideoInputDeviceCapabilitiesPtr> device_capabilities; + std::vector<media::PowerLineFrequency> power_line_capabilities; +}; + +class CONTENT_EXPORT VideoCaptureSourceSettings { + public: + VideoCaptureSourceSettings(); + VideoCaptureSourceSettings(const VideoCaptureSourceSettings& other); + VideoCaptureSourceSettings(VideoCaptureSourceSettings&& other); + VideoCaptureSourceSettings(const std::string& device_id, + const media::VideoCaptureFormat& format, + ::mojom::FacingMode facing_mode, + media::PowerLineFrequency power_line_frequency); + ~VideoCaptureSourceSettings(); + VideoCaptureSourceSettings& operator=( + const VideoCaptureSourceSettings& other); + VideoCaptureSourceSettings& operator=(VideoCaptureSourceSettings&& other); + + // Accessors for easier interaction with blink constraint classes. + blink::WebString GetFacingMode() const; + long GetPowerLineFrequency() const; + long GetWidth() const; + long GetHeight() const; + double GetFrameRate() const; + blink::WebString GetDeviceId() const; + + const media::VideoCaptureFormat& format() const { return format_; } + const std::string& device_id() const { return device_id_; } + ::mojom::FacingMode facing_mode() const { return facing_mode_; } + media::PowerLineFrequency power_line_frequency() const { + return power_line_frequency_; + } + + private: + std::string device_id_; + media::VideoCaptureFormat format_; + ::mojom::FacingMode facing_mode_; + media::PowerLineFrequency power_line_frequency_; +}; + +struct CONTENT_EXPORT VideoCaptureSourceSelectionResult { + VideoCaptureSourceSelectionResult(); + VideoCaptureSourceSelectionResult( + const VideoCaptureSourceSelectionResult& other); + VideoCaptureSourceSelectionResult(VideoCaptureSourceSelectionResult&& other); + ~VideoCaptureSourceSelectionResult(); + VideoCaptureSourceSelectionResult& operator=( + const VideoCaptureSourceSelectionResult& other); + VideoCaptureSourceSelectionResult& operator=( + VideoCaptureSourceSelectionResult&& other); + + bool has_value() const { return failed_constraint_name == nullptr; } + + VideoCaptureSourceSettings settings; + const char* failed_constraint_name; +}; + +// This function performs source and source-settings selection based on +// the given |capabilities| and |constraints|. +// Chromium performs constraint resolution in two steps. First, a source and its +// settings are selected; then a track is created, connected to the source, and +// finally the track settings are selected. This function implements an +// algorithm for the first step. Sources are not a user-visible concept, so the +// spec only specifies an algorithm for track settings. +// This algorithm for sources is compatible with the spec algorithm for tracks, +// as defined in https://w3c.github.io/mediacapture-main/#dfn-selectsettings, +// but it is customized to account for differences between sources and tracks, +// and to break ties when multiple source settings are equally good according to +// the spec algorithm. +// The main difference between a source and a track with regards to the spec +// algorithm is that a candidate source can support a range of values for some +// constraints while a candidate track supports a single value. For example, +// cropping allows a source with native resolution AxB to support the range of +// resolutions from 1x1 to AxB. +// Only candidates that satisfy the basic constraint set are valid. If no +// candidate can satisfy the basic constraint set, this function returns +// a result without a valid |settings| field and with the name of a failed +// constraint in field |failed_constraint_name|. If at least one candidate that +// satisfies the basic constraint set can be found, this function returns a +// result with a valid |settings| field and a null |failed_constraint_name|. +// If there are no candidates at all, this function returns a result with an +// empty string in |failed_constraint_name| and without a valid |settings| +// field. +// The criteria to decide if a valid candidate is better than another one are as +// follows: +// 1. Given advanced constraint sets A[0],A[1]...,A[n], candidate C1 is better +// than candidate C2 if C1 supports the first advanced set for which C1's +// support is different than C2's support. +// Examples: +// * One advanced set, C1 supports it, and C2 does not. C1 is better. +// * Two sets, C1 supports both, C2 supports only the first. C1 is better. +// * Three sets, C1 supports the first and second set, C2 supports the first +// and third set. C1 is better. +// 2. C1 is better than C2 if C1 has a smaller fitness distance than C2. The +// fitness distance depends on the ability of the candidate to support ideal +// values in the basic constraint set. This is the final criterion defined in +// the spec. +// 3. C1 is better than C2 if C1 has a lower Chromium-specific custom distance +// from the basic constraint set. This custom distance is the sum of various +// constraint-specific custom distances. +// For example, if the constraint set specifies a resolution of exactly +// 1000x1000 for a track, then a candidate with a resolution of 1200x1200 +// is better than a candidate with a resolution of 2000x2000. Both settings +// satisfy the constraint set because cropping can be used to produce the +// track setting of 1000x1000, but 1200x1200 is considered better because it +// has lower resource usage. The same criteria applies for each advanced +// constraint set. +// 4. C1 is better than C2 if its native settings have a smaller fitness +// distance. For example, if the ideal resolution is 1000x1000 and C1 has a +// native resolution of 1200x1200, while C2 has a native resolution of +// 2000x2000, then C1 is better because it can support the ideal value with +// lower resource usage. Both C1 and C2 are better than a candidate C3 with +// a native resolution of 999x999, since C3 has a nonzero distance to the +// ideal value and thus has worse fitness according to step 2, even if C3's +// native fitness is better than C1's and C2's. +// 5. C1 is better than C2 if its settings are closer to certain default +// settings that include the device ID, power-line frequency, resolution, and +// frame rate, in that order. Note that there is no default facing mode or +// aspect ratio. +VideoCaptureSourceSelectionResult CONTENT_EXPORT +SelectVideoCaptureSourceSettings(const VideoCaptureCapabilities& capabilities, + const blink::WebMediaConstraints& constraints); + +} // namespace content + +#endif // CONTENT_RENDERER_MEDIA_MEDIA_STREAM_CONSTRAINTS_UTIL_VIDEO_SOURCE_H_
diff --git a/content/renderer/media/media_stream_constraints_util_video_source_unittest.cc b/content/renderer/media/media_stream_constraints_util_video_source_unittest.cc new file mode 100644 index 0000000..c8e697ce --- /dev/null +++ b/content/renderer/media/media_stream_constraints_util_video_source_unittest.cc
@@ -0,0 +1,1277 @@ +// 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 "content/renderer/media/media_stream_constraints_util_video_source.h" + +#include <algorithm> +#include <utility> + +#include "base/optional.h" +#include "content/renderer/media/media_stream_video_source.h" +#include "content/renderer/media/mock_constraint_factory.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/public/platform/WebMediaConstraints.h" + +namespace content { + +namespace { + +const char kDeviceID1[] = "fake_device_1"; +const char kDeviceID2[] = "fake_device_2"; +const char kDeviceID3[] = "fake_device_3"; +} + +class MediaStreamConstraintsUtilVideoSourceTest : public testing::Test { + public: + void SetUp() override { + // Default device. It is default because it is the first in the enumeration. + ::mojom::VideoInputDeviceCapabilitiesPtr device = + ::mojom::VideoInputDeviceCapabilities::New(); + device->device_id = kDeviceID1; + device->facing_mode = ::mojom::FacingMode::NONE; + device->formats = { + media::VideoCaptureFormat(gfx::Size(200, 200), 40.0f, + media::PIXEL_FORMAT_I420), + // This entry is is the closest to defaults. + media::VideoCaptureFormat(gfx::Size(500, 500), 40.0f, + media::PIXEL_FORMAT_I420), + media::VideoCaptureFormat(gfx::Size(1000, 1000), 20.0f, + media::PIXEL_FORMAT_I420), + }; + capabilities_.device_capabilities.push_back(std::move(device)); + + // A low-resolution device. + device = ::mojom::VideoInputDeviceCapabilities::New(); + device->device_id = kDeviceID2; + device->facing_mode = ::mojom::FacingMode::ENVIRONMENT; + device->formats = { + media::VideoCaptureFormat(gfx::Size(40, 30), 20.0f, + media::PIXEL_FORMAT_I420), + media::VideoCaptureFormat(gfx::Size(320, 240), 30.0f, + media::PIXEL_FORMAT_I420), + // This format has defaults for all settings + media::VideoCaptureFormat( + gfx::Size(MediaStreamVideoSource::kDefaultWidth, + MediaStreamVideoSource::kDefaultHeight), + MediaStreamVideoSource::kDefaultFrameRate, + media::PIXEL_FORMAT_I420), + media::VideoCaptureFormat(gfx::Size(800, 600), 20.0f, + media::PIXEL_FORMAT_I420), + }; + capabilities_.device_capabilities.push_back(std::move(device)); + + // A high-resolution device. + device = ::mojom::VideoInputDeviceCapabilities::New(); + device->device_id = kDeviceID3; + device->facing_mode = ::mojom::FacingMode::USER; + device->formats = { + media::VideoCaptureFormat(gfx::Size(320, 240), 10.0f, + media::PIXEL_FORMAT_I420), + media::VideoCaptureFormat(gfx::Size(640, 480), 10.0f, + media::PIXEL_FORMAT_I420), + // This format has defaults for all settings + media::VideoCaptureFormat( + gfx::Size(MediaStreamVideoSource::kDefaultWidth, + MediaStreamVideoSource::kDefaultHeight), + MediaStreamVideoSource::kDefaultFrameRate, + media::PIXEL_FORMAT_I420), + media::VideoCaptureFormat(gfx::Size(1280, 720), 60.0f, + media::PIXEL_FORMAT_I420), + media::VideoCaptureFormat(gfx::Size(1920, 1080), 60.0f, + media::PIXEL_FORMAT_I420), + media::VideoCaptureFormat(gfx::Size(2304, 1536), 10.0f, + media::PIXEL_FORMAT_I420), + }; + capabilities_.device_capabilities.push_back(std::move(device)); + + capabilities_.power_line_capabilities = { + media::PowerLineFrequency::FREQUENCY_DEFAULT, + media::PowerLineFrequency::FREQUENCY_50HZ, + media::PowerLineFrequency::FREQUENCY_60HZ, + }; + + default_device_ = capabilities_.device_capabilities[0].get(); + low_res_device_ = capabilities_.device_capabilities[1].get(); + high_res_device_ = capabilities_.device_capabilities[2].get(); + default_closest_format_ = &default_device_->formats[1]; + low_res_closest_format_ = &low_res_device_->formats[2]; + high_res_closest_format_ = &high_res_device_->formats[2]; + high_res_highest_format_ = &high_res_device_->formats[5]; + } + + protected: + VideoCaptureSourceSelectionResult SelectSettings() { + blink::WebMediaConstraints constraints = + constraint_factory_.CreateWebMediaConstraints(); + return SelectVideoCaptureSourceSettings(capabilities_, constraints); + } + + VideoCaptureCapabilities capabilities_; + const mojom::VideoInputDeviceCapabilities* default_device_; + const mojom::VideoInputDeviceCapabilities* low_res_device_; + const mojom::VideoInputDeviceCapabilities* high_res_device_; + // Closest formats to the default settings. + const media::VideoCaptureFormat* default_closest_format_; + const media::VideoCaptureFormat* low_res_closest_format_; + const media::VideoCaptureFormat* high_res_closest_format_; + const media::VideoCaptureFormat* high_res_highest_format_; + + MockConstraintFactory constraint_factory_; +}; + +// The Unconstrained test checks the default selection criteria. +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, Unconstrained) { + constraint_factory_.Reset(); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // Should select the default device with closest-to-default settings. + EXPECT_EQ(default_device_->device_id, result.settings.device_id()); + EXPECT_EQ(default_device_->facing_mode, result.settings.facing_mode()); + EXPECT_EQ(*default_closest_format_, result.settings.format()); +} + +// The "Overconstrained" tests verify that failure of any single required +// constraint results in failure to select a candidate. +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, OverconstrainedOnDeviceID) { + constraint_factory_.Reset(); + constraint_factory_.basic().deviceId.setExact( + blink::WebString::fromASCII("NONEXISTING")); + auto result = SelectSettings(); + EXPECT_FALSE(result.has_value()); + EXPECT_EQ(constraint_factory_.basic().deviceId.name(), + result.failed_constraint_name); +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, OverconstrainedOnFacingMode) { + constraint_factory_.Reset(); + // No device in |capabilities_| has facing mode equal to LEFT. + constraint_factory_.basic().facingMode.setExact( + blink::WebString::fromASCII("left")); + auto result = SelectSettings(); + EXPECT_FALSE(result.has_value()); + EXPECT_EQ(constraint_factory_.basic().facingMode.name(), + result.failed_constraint_name); +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, OverconstrainedOnHeight) { + constraint_factory_.Reset(); + constraint_factory_.basic().height.setExact(123467890); + auto result = SelectSettings(); + EXPECT_FALSE(result.has_value()); + EXPECT_EQ(constraint_factory_.basic().height.name(), + result.failed_constraint_name); + + constraint_factory_.Reset(); + constraint_factory_.basic().height.setMin(123467890); + result = SelectSettings(); + EXPECT_FALSE(result.has_value()); + EXPECT_EQ(constraint_factory_.basic().height.name(), + result.failed_constraint_name); + + constraint_factory_.Reset(); + constraint_factory_.basic().height.setMax(0); + result = SelectSettings(); + EXPECT_FALSE(result.has_value()); + EXPECT_EQ(constraint_factory_.basic().height.name(), + result.failed_constraint_name); +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, OverconstrainedOnWidth) { + constraint_factory_.Reset(); + constraint_factory_.basic().width.setExact(123467890); + auto result = SelectSettings(); + EXPECT_FALSE(result.has_value()); + EXPECT_EQ(constraint_factory_.basic().width.name(), + result.failed_constraint_name); + + constraint_factory_.Reset(); + constraint_factory_.basic().width.setMin(123467890); + result = SelectSettings(); + EXPECT_FALSE(result.has_value()); + EXPECT_EQ(constraint_factory_.basic().width.name(), + result.failed_constraint_name); + + constraint_factory_.Reset(); + constraint_factory_.basic().width.setMax(0); + result = SelectSettings(); + EXPECT_FALSE(result.has_value()); + EXPECT_EQ(constraint_factory_.basic().width.name(), + result.failed_constraint_name); +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, + OverconstrainedOnAspectRatio) { + constraint_factory_.Reset(); + constraint_factory_.basic().aspectRatio.setExact(123467890.0); + auto result = SelectSettings(); + EXPECT_FALSE(result.has_value()); + EXPECT_EQ(constraint_factory_.basic().aspectRatio.name(), + result.failed_constraint_name); + + constraint_factory_.Reset(); + constraint_factory_.basic().aspectRatio.setMin(123467890.0); + result = SelectSettings(); + EXPECT_FALSE(result.has_value()); + EXPECT_EQ(constraint_factory_.basic().aspectRatio.name(), + result.failed_constraint_name); + + constraint_factory_.Reset(); + // This value is lower than the minimum supported by sources. + double kLowAspectRatio = 0.01; + constraint_factory_.basic().aspectRatio.setMax(kLowAspectRatio); + result = SelectSettings(); + EXPECT_FALSE(result.has_value()); + EXPECT_EQ(constraint_factory_.basic().aspectRatio.name(), + result.failed_constraint_name); +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, OverconstrainedOnFrameRate) { + constraint_factory_.Reset(); + constraint_factory_.basic().frameRate.setExact(123467890.0); + auto result = SelectSettings(); + EXPECT_FALSE(result.has_value()); + EXPECT_EQ(constraint_factory_.basic().frameRate.name(), + result.failed_constraint_name); + + constraint_factory_.Reset(); + constraint_factory_.basic().frameRate.setMin(123467890.0); + result = SelectSettings(); + EXPECT_FALSE(result.has_value()); + EXPECT_EQ(constraint_factory_.basic().frameRate.name(), + result.failed_constraint_name); + + constraint_factory_.Reset(); + constraint_factory_.basic().frameRate.setMax(0.0); + result = SelectSettings(); + EXPECT_FALSE(result.has_value()); + EXPECT_EQ(constraint_factory_.basic().frameRate.name(), + result.failed_constraint_name); +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, + OverconstrainedOnPowerLineFrequency) { + constraint_factory_.Reset(); + constraint_factory_.basic().googPowerLineFrequency.setExact(123467890); + auto result = SelectSettings(); + EXPECT_FALSE(result.has_value()); + EXPECT_EQ(constraint_factory_.basic().googPowerLineFrequency.name(), + result.failed_constraint_name); + + constraint_factory_.Reset(); + constraint_factory_.basic().googPowerLineFrequency.setMin(123467890); + result = SelectSettings(); + EXPECT_FALSE(result.has_value()); + EXPECT_EQ(constraint_factory_.basic().googPowerLineFrequency.name(), + result.failed_constraint_name); + + constraint_factory_.Reset(); + constraint_factory_.basic().googPowerLineFrequency.setMax(-1); + result = SelectSettings(); + EXPECT_FALSE(result.has_value()); + EXPECT_EQ(constraint_factory_.basic().googPowerLineFrequency.name(), + result.failed_constraint_name); +} + +// The "Mandatory" and "Ideal" tests check that various selection criteria work +// for each individual constraint in the basic constraint set. +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryDeviceID) { + constraint_factory_.Reset(); + constraint_factory_.basic().deviceId.setExact( + blink::WebString::fromASCII(default_device_->device_id)); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(default_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*default_closest_format_, result.settings.format()); + EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT, + result.settings.power_line_frequency()); + + constraint_factory_.basic().deviceId.setExact( + blink::WebString::fromASCII(low_res_device_->device_id)); + result = SelectSettings(); + EXPECT_EQ(low_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*low_res_closest_format_, result.settings.format()); + EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT, + result.settings.power_line_frequency()); + + constraint_factory_.basic().deviceId.setExact( + blink::WebString::fromASCII(high_res_device_->device_id)); + result = SelectSettings(); + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*high_res_closest_format_, result.settings.format()); + EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT, + result.settings.power_line_frequency()); +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryFacingMode) { + constraint_factory_.Reset(); + constraint_factory_.basic().facingMode.setExact( + blink::WebString::fromASCII("environment")); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(::mojom::FacingMode::ENVIRONMENT, result.settings.facing_mode()); + // Only the low-res device supports environment facing mode. Should select + // default settings for everything else. + EXPECT_EQ(low_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*low_res_closest_format_, result.settings.format()); + EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT, + result.settings.power_line_frequency()); + + constraint_factory_.basic().facingMode.setExact( + blink::WebString::fromASCII("user")); + result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(::mojom::FacingMode::USER, result.settings.facing_mode()); + // Only the high-res device supports user facing mode. Should select default + // settings for everything else. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*high_res_closest_format_, result.settings.format()); + EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT, + result.settings.power_line_frequency()); +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryPowerLineFrequency) { + constraint_factory_.Reset(); + const media::PowerLineFrequency kPowerLineFrequencies[] = { + media::PowerLineFrequency::FREQUENCY_50HZ, + media::PowerLineFrequency::FREQUENCY_60HZ}; + for (auto power_line_frequency : kPowerLineFrequencies) { + constraint_factory_.basic().googPowerLineFrequency.setExact( + static_cast<long>(power_line_frequency)); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(power_line_frequency, result.settings.power_line_frequency()); + // The default device and settings closest to the default should be + // selected. + EXPECT_EQ(default_device_->device_id, result.settings.device_id()); + EXPECT_EQ(default_device_->facing_mode, result.settings.facing_mode()); + EXPECT_EQ(*default_closest_format_, result.settings.format()); + } +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryExactHeight) { + constraint_factory_.Reset(); + const int kHeight = MediaStreamVideoSource::kDefaultHeight; + constraint_factory_.basic().height.setExact(kHeight); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // All devices in |capabilities_| support the requested height. The algorithm + // should prefer the first device that supports the requested height natively, + // which is the low-res device. + EXPECT_EQ(low_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(kHeight, result.settings.GetHeight()); + + const int kLargeHeight = 1500; + constraint_factory_.basic().height.setExact(kLargeHeight); + result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // Only the high-res device at the highest resolution supports the requested + // height, even if not natively. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*high_res_highest_format_, result.settings.format()); +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMinHeight) { + constraint_factory_.Reset(); + const int kHeight = MediaStreamVideoSource::kDefaultHeight; + constraint_factory_.basic().height.setMin(kHeight); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // All devices in |capabilities_| support the requested height range. The + // algorithm should prefer the default device. + EXPECT_EQ(default_device_->device_id, result.settings.device_id()); + EXPECT_LE(kHeight, result.settings.GetHeight()); + + const int kLargeHeight = 1500; + constraint_factory_.basic().height.setMin(kLargeHeight); + result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // Only the high-res device at the highest resolution supports the requested + // height range. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*high_res_highest_format_, result.settings.format()); +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMaxHeight) { + constraint_factory_.Reset(); + const int kLowHeight = 20; + constraint_factory_.basic().height.setMax(kLowHeight); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // All devices in |capabilities_| support the requested height range. The + // algorithm should prefer the settings that natively exceed the requested + // maximum by the lowest amount. In this case it is the low-res device. + EXPECT_EQ(low_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(low_res_device_->formats[0], result.settings.format()); +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryHeightRange) { + constraint_factory_.Reset(); + { + const int kMinHeight = 480; + const int kMaxHeight = 720; + constraint_factory_.basic().height.setMin(kMinHeight); + constraint_factory_.basic().height.setMax(kMaxHeight); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + EXPECT_GE(result.settings.GetHeight(), kMinHeight); + EXPECT_LE(result.settings.GetHeight(), kMaxHeight); + // All devices in |capabilities_| support the constraint range. The + // algorithm should prefer the default device since it has at least one + // native format (the closest-to-default format) included in the requested + // range. + EXPECT_EQ(default_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*default_closest_format_, result.settings.format()); + } + + { + const int kMinHeight = 550; + const int kMaxHeight = 650; + constraint_factory_.basic().height.setMin(kMinHeight); + constraint_factory_.basic().height.setMax(kMaxHeight); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + EXPECT_GE(result.settings.GetHeight(), kMinHeight); + EXPECT_LE(result.settings.GetHeight(), kMaxHeight); + // In this case, the algorithm should prefer the low-res device since it is + // the first device with a native format (800x600) included in the requested + // range. + EXPECT_EQ(low_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(800, result.settings.GetWidth()); + EXPECT_EQ(600, result.settings.GetHeight()); + } + + { + const int kMinHeight = 700; + const int kMaxHeight = 800; + constraint_factory_.basic().height.setMin(kMinHeight); + constraint_factory_.basic().height.setMax(kMaxHeight); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + EXPECT_GE(result.settings.GetHeight(), kMinHeight); + EXPECT_LE(result.settings.GetHeight(), kMaxHeight); + // In this case, the algorithm should prefer the high-res device since it is + // the only device with a native format (1280x720) included in the requested + // range. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(1280, result.settings.GetWidth()); + EXPECT_EQ(720, result.settings.GetHeight()); + } +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, IdealHeight) { + constraint_factory_.Reset(); + { + const int kIdealHeight = 480; + constraint_factory_.basic().height.setIdeal(kIdealHeight); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // The algorithm should select the first device that supports the ideal + // height natively. + EXPECT_EQ(low_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(kIdealHeight, result.settings.GetHeight()); + } + + { + const int kIdealHeight = 481; + constraint_factory_.basic().height.setIdeal(kIdealHeight); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // In this case, the default device is selected because it can satisfy the + // ideal at a lower cost than the other devices (500 vs 600 or 720). + // Note that a native resolution of 480 is further from the ideal than + // 500 cropped to 480. + EXPECT_EQ(default_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*default_closest_format_, result.settings.format()); + } + + { + const int kIdealHeight = 1079; + constraint_factory_.basic().height.setIdeal(kIdealHeight); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // In this case, the high-res device has two configurations that satisfy + // the ideal value (1920x1080 and 2304x1536). Select the one with shortest + // native distance to the ideal value (1920x1080). + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(1920, result.settings.GetWidth()); + EXPECT_EQ(1080, result.settings.GetHeight()); + } + + { + const int kIdealHeight = 1200; + constraint_factory_.basic().height.setIdeal(kIdealHeight); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // The algorithm must the select the only device that can satisfy the ideal, + // which is the high-res device at the highest resolution. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*high_res_highest_format_, result.settings.format()); + } +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryExactWidth) { + constraint_factory_.Reset(); + const int kWidth = 640; + constraint_factory_.basic().width.setExact(kWidth); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // All devices in |capabilities_| support the requested width. The algorithm + // should prefer the first device that supports the requested width natively, + // which is the low-res device. + EXPECT_EQ(low_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(kWidth, result.settings.GetWidth()); + + const int kLargeWidth = 2000; + constraint_factory_.basic().width.setExact(kLargeWidth); + result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + EXPECT_LE(kLargeWidth, result.settings.GetWidth()); + // Only the high-res device at the highest resolution supports the requested + // width, even if not natively. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*high_res_highest_format_, result.settings.format()); +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMinWidth) { + constraint_factory_.Reset(); + const int kWidth = 640; + constraint_factory_.basic().width.setMin(kWidth); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // All devices in |capabilities_| support the requested width range. The + // algorithm should prefer the default device at 1000x1000, which is the + // first configuration that satisfies the minimum width. + EXPECT_EQ(default_device_->device_id, result.settings.device_id()); + EXPECT_LE(kWidth, result.settings.GetWidth()); + EXPECT_EQ(1000, result.settings.GetWidth()); + EXPECT_EQ(1000, result.settings.GetHeight()); + + const int kLargeWidth = 2000; + constraint_factory_.basic().width.setMin(kLargeWidth); + result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // Only the high-res device at the highest resolution supports the requested + // minimum width. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_LE(kLargeWidth, result.settings.GetWidth()); + EXPECT_EQ(*high_res_highest_format_, result.settings.format()); +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMaxWidth) { + constraint_factory_.Reset(); + const int kLowWidth = 30; + constraint_factory_.basic().width.setMax(kLowWidth); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // All devices in |capabilities_| support the requested width range. The + // algorithm should prefer the settings that natively exceed the requested + // maximum by the lowest amount. In this case it is the low-res device at its + // lowest resolution. + EXPECT_EQ(low_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(low_res_device_->formats[0], result.settings.format()); +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryWidthRange) { + constraint_factory_.Reset(); + { + const int kMinWidth = 640; + const int kMaxWidth = 1280; + constraint_factory_.basic().width.setMin(kMinWidth); + constraint_factory_.basic().width.setMax(kMaxWidth); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + EXPECT_GE(result.settings.GetWidth(), kMinWidth); + EXPECT_LE(result.settings.GetWidth(), kMaxWidth); + // All devices in |capabilities_| support the constraint range. The + // algorithm should prefer the default device since it has at least one + // native format (1000x1000) included in the requested range. + EXPECT_EQ(default_device_->device_id, result.settings.device_id()); + EXPECT_EQ(1000, result.settings.GetWidth()); + EXPECT_EQ(1000, result.settings.GetHeight()); + } + + { + const int kMinWidth = 750; + const int kMaxWidth = 850; + constraint_factory_.basic().width.setMin(kMinWidth); + constraint_factory_.basic().width.setMax(kMaxWidth); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + EXPECT_GE(result.settings.GetWidth(), kMinWidth); + EXPECT_LE(result.settings.GetWidth(), kMaxWidth); + // In this case, the algorithm should prefer the low-res device since it is + // the first device with a native format (800x600) included in the requested + // range. + EXPECT_EQ(low_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(800, result.settings.GetWidth()); + EXPECT_EQ(600, result.settings.GetHeight()); + } + + { + const int kMinWidth = 1900; + const int kMaxWidth = 2000; + constraint_factory_.basic().width.setMin(kMinWidth); + constraint_factory_.basic().width.setMax(kMaxWidth); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + EXPECT_GE(result.settings.GetWidth(), kMinWidth); + EXPECT_LE(result.settings.GetWidth(), kMaxWidth); + // In this case, the algorithm should prefer the high-res device since it is + // the only device with a native format (1920x1080) included in the + // requested range. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(1920, result.settings.GetWidth()); + EXPECT_EQ(1080, result.settings.GetHeight()); + } +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, IdealWidth) { + constraint_factory_.Reset(); + { + const int kIdealWidth = 320; + constraint_factory_.basic().width.setIdeal(kIdealWidth); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // The algorithm should select the first device that supports the ideal + // width natively, which is the low-res device at 320x240. + EXPECT_EQ(low_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(kIdealWidth, result.settings.GetWidth()); + } + + { + const int kIdealWidth = 321; + constraint_factory_.basic().width.setIdeal(kIdealWidth); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // In this case, the default device is selected because it can satisfy the + // ideal at a lower cost than the other devices (500 vs 640). + // Note that a native resolution of 320 is further from the ideal value of + // 321 than 500 cropped to 321. + EXPECT_EQ(default_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*default_closest_format_, result.settings.format()); + } + + { + const int kIdealWidth = 2000; + constraint_factory_.basic().width.setIdeal(kIdealWidth); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // The algorithm must the select the only device that can satisfy the ideal. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*high_res_highest_format_, result.settings.format()); + } + + { + const int kIdealWidth = 3000; + constraint_factory_.basic().width.setIdeal(kIdealWidth); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // The algorithm must the select the device and setting with less distance + // to the ideal. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*high_res_highest_format_, result.settings.format()); + } +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryExactFrameRate) { + constraint_factory_.Reset(); + const double kFrameRate = MediaStreamVideoSource::kDefaultFrameRate; + constraint_factory_.basic().frameRate.setExact(kFrameRate); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // All devices in |capabilities_| support the requested frame rate. The + // algorithm should prefer the first device that supports the requested frame + // rate natively, which is the low-res device at 640x480x30Hz. + EXPECT_EQ(low_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(kFrameRate, result.settings.GetFrameRate()); + EXPECT_EQ(640, result.settings.GetWidth()); + EXPECT_EQ(480, result.settings.GetHeight()); + + const double kLargeFrameRate = 50; + constraint_factory_.basic().frameRate.setExact(kLargeFrameRate); + result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // Only the high-res device supports the requested frame rate, even if not + // natively. The least expensive configuration that supports the requested + // frame rate is 1280x720x60Hz. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(60.0, result.settings.GetFrameRate()); + EXPECT_EQ(1280, result.settings.GetWidth()); + EXPECT_EQ(720, result.settings.GetHeight()); +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMinFrameRate) { + constraint_factory_.Reset(); + const double kFrameRate = MediaStreamVideoSource::kDefaultFrameRate; + constraint_factory_.basic().frameRate.setMin(kFrameRate); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // All devices in |capabilities_| support the requested frame-rate range. The + // algorithm should prefer the default device. + EXPECT_EQ(default_device_->device_id, result.settings.device_id()); + // The format closest to the default satisfies the constraint. + EXPECT_EQ(*default_closest_format_, result.settings.format()); + + const double kLargeFrameRate = 50; + constraint_factory_.basic().frameRate.setMin(kLargeFrameRate); + result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // Only the high-res device supports the requested frame-rate range. + // The least expensive configuration is 1280x720x60Hz. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_LE(kLargeFrameRate, result.settings.GetFrameRate()); + EXPECT_EQ(1280, result.settings.GetWidth()); + EXPECT_EQ(720, result.settings.GetHeight()); +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMaxFrameRate) { + constraint_factory_.Reset(); + const double kLowFrameRate = 10; + constraint_factory_.basic().frameRate.setMax(kLowFrameRate); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // All devices in |capabilities_| support the requested frame-rate range. The + // algorithm should prefer the settings that natively exceed the requested + // maximum by the lowest amount. In this case it is the high-res device with + // default resolution . + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(kLowFrameRate, result.settings.GetFrameRate()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, + result.settings.GetHeight()); + EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.settings.GetWidth()); +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryFrameRateRange) { + constraint_factory_.Reset(); + { + const double kMinFrameRate = 10; + const double kMaxFrameRate = 40; + constraint_factory_.basic().frameRate.setMin(kMinFrameRate); + constraint_factory_.basic().frameRate.setMax(kMaxFrameRate); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + EXPECT_LE(kMinFrameRate, result.settings.GetFrameRate()); + EXPECT_GE(kMaxFrameRate, result.settings.GetFrameRate()); + // All devices in |capabilities_| support the constraint range. The + // algorithm should prefer the default device since its closest-to-default + // format has a frame rate included in the requested range. + EXPECT_EQ(default_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*default_closest_format_, result.settings.format()); + } + + { + const double kMinFrameRate = 25; + const double kMaxFrameRate = 35; + constraint_factory_.basic().frameRate.setMin(kMinFrameRate); + constraint_factory_.basic().frameRate.setMax(kMaxFrameRate); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + EXPECT_GE(result.settings.GetFrameRate(), kMinFrameRate); + EXPECT_LE(result.settings.GetFrameRate(), kMaxFrameRate); + // In this case, the algorithm should prefer the low-res device since it is + // the first device with a native frame rate included in the requested + // range. The default resolution should be preferred as secondary criterion. + EXPECT_EQ(low_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*low_res_closest_format_, result.settings.format()); + } + + { + const double kMinFrameRate = 50; + const double kMaxFrameRate = 70; + constraint_factory_.basic().frameRate.setMin(kMinFrameRate); + constraint_factory_.basic().frameRate.setMax(kMaxFrameRate); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + EXPECT_GE(result.settings.GetFrameRate(), kMinFrameRate); + EXPECT_LE(result.settings.GetFrameRate(), kMaxFrameRate); + // In this case, the algorithm should prefer the high-res device since it is + // the only device with a native format included in the requested range. + // The 1280x720 resolution should be selected due to closeness to default + // settings, which is the second tie-breaker criterion that applies. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(1280, result.settings.GetWidth()); + EXPECT_EQ(720, result.settings.GetHeight()); + } +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, IdealFrameRate) { + constraint_factory_.Reset(); + { + const double kIdealFrameRate = MediaStreamVideoSource::kDefaultFrameRate; + constraint_factory_.basic().frameRate.setIdeal(kIdealFrameRate); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // The algorithm should select the first configuration that supports the + // ideal frame rate natively, which is the low-res device. Default + // resolution should be selected as secondary criterion. + EXPECT_EQ(low_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*low_res_closest_format_, result.settings.format()); + } + + { + const double kIdealFrameRate = 31; + constraint_factory_.basic().frameRate.setIdeal(kIdealFrameRate); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // In this case, the default device is selected because it can satisfy the + // ideal at a lower cost than the other devices (40 vs 60). + // Note that a native frame rate of 30 is further from the ideal than + // 31 adjusted to 30. + EXPECT_EQ(default_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*default_closest_format_, result.settings.format()); + } + + { + const double kIdealFrameRate = 55; + constraint_factory_.basic().frameRate.setIdeal(kIdealFrameRate); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // The high-res device format 1280x720x60.0 must be selected because its + // frame rate can satisfy the ideal frame rate and has resolution closest + // to the default. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(1280, result.settings.GetWidth()); + EXPECT_EQ(720, result.settings.GetHeight()); + EXPECT_EQ(60, result.settings.GetFrameRate()); + } + + { + const double kIdealFrameRate = 100; + constraint_factory_.basic().frameRate.setIdeal(kIdealFrameRate); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // The algorithm must select settings with frame rate closest to the ideal. + // The high-res device format 1280x720x60.0 must be selected because its + // frame rate it closest to the ideal value and it has resolution closest to + // the default. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(1280, result.settings.GetWidth()); + EXPECT_EQ(720, result.settings.GetHeight()); + EXPECT_EQ(60, result.settings.GetFrameRate()); + } +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryExactAspectRatio) { + constraint_factory_.Reset(); + const double kAspectRatio = 4.0 / 3.0; + constraint_factory_.basic().aspectRatio.setExact(kAspectRatio); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + double min_width = 1.0; + double max_width = result.settings.GetWidth(); + double min_height = 1.0; + double max_height = result.settings.GetHeight(); + double min_aspect_ratio = min_width / max_height; + double max_aspect_ratio = max_width / min_height; + // The requested aspect ratio must be within the supported range. + EXPECT_GE(kAspectRatio, min_aspect_ratio); + EXPECT_LE(kAspectRatio, max_aspect_ratio); + // All devices in |capabilities_| support the requested aspect ratio. + // The algorithm should prefer the first device that supports the requested + // aspect ratio. + EXPECT_EQ(default_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*default_closest_format_, result.settings.format()); + + const long kMinWidth = 500; + const long kMaxWidth = 1000; + const long kMaxHeight = 500; + constraint_factory_.basic().height.setMax(kMaxHeight); + constraint_factory_.basic().width.setMin(kMinWidth); + constraint_factory_.basic().width.setMax(kMaxWidth); + constraint_factory_.basic().aspectRatio.setExact(kAspectRatio); + result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + min_width = std::max(1L, kMinWidth); + max_width = std::min(result.settings.GetWidth(), kMaxWidth); + min_height = 1.0; + max_height = std::min(result.settings.GetHeight(), kMaxHeight); + min_aspect_ratio = min_width / max_height; + max_aspect_ratio = max_width / min_height; + // The requested aspect ratio must be within the supported range. + EXPECT_GE(kAspectRatio, min_aspect_ratio); + EXPECT_LE(kAspectRatio, max_aspect_ratio); + // The default device can support the requested aspect ratio with the default + // settings (500x500) using cropping. + EXPECT_EQ(default_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*default_closest_format_, result.settings.format()); + + const long kMinHeight = 480; + constraint_factory_.basic().height.setMin(kMinHeight); + constraint_factory_.basic().height.setMax(kMaxHeight); + constraint_factory_.basic().width.setMin(kMinWidth); + constraint_factory_.basic().width.setMax(kMaxWidth); + constraint_factory_.basic().aspectRatio.setExact(kAspectRatio); + result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + min_width = std::max(1L, kMinWidth); + max_width = std::min(result.settings.GetWidth(), kMaxWidth); + min_height = std::max(1L, kMinHeight); + max_height = std::min(result.settings.GetHeight(), kMaxHeight); + min_aspect_ratio = min_width / max_height; + max_aspect_ratio = max_width / min_height; + // The requested aspect ratio must be within the supported range. + EXPECT_GE(kAspectRatio, min_aspect_ratio); + EXPECT_LE(kAspectRatio, max_aspect_ratio); + // Given resolution constraints, the default device with closest-to-default + // settings cannot satisfy the required aspect ratio. + // The first device that can do it is the low-res device with a native + // resolution of 640x480. Higher resolutions for the default device are more + // penalized by the constraints than the default native resolution of the + // low-res device. + EXPECT_EQ(low_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*low_res_closest_format_, result.settings.format()); +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMinAspectRatio) { + constraint_factory_.Reset(); + const double kAspectRatio = 4.0 / 3.0; + constraint_factory_.basic().aspectRatio.setMin(kAspectRatio); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + double max_width = result.settings.GetWidth(); + double min_height = 1.0; + double max_aspect_ratio = max_width / min_height; + // Minimum constraint aspect ratio must be less than or equal to the maximum + // supported by the source. + EXPECT_LE(kAspectRatio, max_aspect_ratio); + // All devices in |capabilities_| support the requested aspect-ratio range. + // The algorithm should prefer the first device that supports the requested + // aspect-ratio range, which in this case is the default device. + EXPECT_EQ(default_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*default_closest_format_, result.settings.format()); + + const long kMinWidth = 500; + const long kMaxWidth = 1000; + const long kMinHeight = 480; + const long kMaxHeight = 500; + constraint_factory_.basic().width.setMin(kMinWidth); + constraint_factory_.basic().width.setMax(kMaxWidth); + constraint_factory_.basic().height.setMin(kMinHeight); + constraint_factory_.basic().height.setMax(kMaxHeight); + constraint_factory_.basic().aspectRatio.setMin(kAspectRatio); + result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + max_width = std::min(result.settings.GetWidth(), kMaxWidth); + min_height = std::max(1L, kMinHeight); + max_aspect_ratio = max_width / min_height; + // Minimum constraint aspect ratio must be less than or equal to the minimum + // supported by the source. + EXPECT_LE(kAspectRatio, max_aspect_ratio); + // Given resolution constraints, the default device with closest-to-default + // settings cannot satisfy the required minimum aspect ratio (maximum would + // be 500/480). The first device that can is the low-res device with a native + // resolution of 640x480. + // Higher resolutions for the default device are more penalized by the + // constraints than the default native resolution of the low-res device. + EXPECT_EQ(low_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*low_res_closest_format_, result.settings.format()); +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMaxAspectRatio) { + constraint_factory_.Reset(); + const double kAspectRatio = 0.5; + constraint_factory_.basic().aspectRatio.setMax(kAspectRatio); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + double min_width = 1.0; + double max_height = result.settings.GetHeight(); + double min_aspect_ratio = min_width / max_height; + // Minimum constraint aspect ratio must be less than or equal to the maximum + // supported by the source. + EXPECT_GE(kAspectRatio, min_aspect_ratio); + // All devices in |capabilities_| support the requested aspect-ratio range. + // The algorithm should prefer the first device that supports the requested + // aspect-ratio range, which in this case is the default device. + EXPECT_EQ(default_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*default_closest_format_, result.settings.format()); + + const long kExactWidth = 360; + const long kMinHeight = 360; + const long kMaxHeight = 720; + constraint_factory_.basic().width.setExact(kExactWidth); + constraint_factory_.basic().height.setMin(kMinHeight); + constraint_factory_.basic().height.setMax(kMaxHeight); + constraint_factory_.basic().aspectRatio.setMax(kAspectRatio); + result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + min_width = std::max(1L, kExactWidth); + max_height = std::min(result.settings.GetHeight(), kMaxHeight); + min_aspect_ratio = min_width / max_height; + // Minimum constraint aspect ratio must be less than or equal to the minimum + // supported by the source. + EXPECT_GE(kAspectRatio, min_aspect_ratio); + // Given resolution constraints, the default device with closest-to-default + // settings cannot satisfy the required maximum aspect ratio (maximum would + // be 360/500). + // The high-res device with a native resolution of 1280x720 can support + // 360x720 with cropping with less penalty than the default device at + // 1000x1000. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(1280, result.settings.GetWidth()); + EXPECT_EQ(720, result.settings.GetHeight()); +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryAspectRatioRange) { + constraint_factory_.Reset(); + { + const double kMinAspectRatio = 0.5; + const double kMaxAspectRatio = 1.0; + + constraint_factory_.basic().aspectRatio.setMin(kMinAspectRatio); + constraint_factory_.basic().aspectRatio.setMax(kMaxAspectRatio); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + double min_width = 1.0; + double max_width = result.settings.GetWidth(); + double min_height = 1.0; + double max_height = result.settings.GetHeight(); + double min_aspect_ratio = min_width / max_height; + double max_aspect_ratio = max_width / min_height; + // Constraint aspect-ratio range must have nonempty intersection with + // supported range. + EXPECT_LE(kMinAspectRatio, max_aspect_ratio); + EXPECT_GE(kMaxAspectRatio, min_aspect_ratio); + // All devices in |capabilities_| support the requested aspect-ratio range. + // The algorithm should prefer the first device that supports the requested + // aspect-ratio range, which in this case is the default device. + EXPECT_EQ(default_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*default_closest_format_, result.settings.format()); + } + + { + const double kMinAspectRatio = 3.0; + const double kMaxAspectRatio = 4.0; + + const long kExactHeight = 600; + constraint_factory_.Reset(); + constraint_factory_.basic().height.setMin(kExactHeight); + constraint_factory_.basic().aspectRatio.setMin(kMinAspectRatio); + constraint_factory_.basic().aspectRatio.setMax(kMaxAspectRatio); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + double min_width = 1.0; + double max_width = result.settings.GetWidth(); + double min_height = 1.0; + double max_height = result.settings.GetHeight(); + double min_aspect_ratio = min_width / max_height; + double max_aspect_ratio = max_width / min_height; + // Constraint aspect-ratio range must have nonempty intersection with + // supported range. + EXPECT_LE(kMinAspectRatio, max_aspect_ratio); + EXPECT_GE(kMaxAspectRatio, min_aspect_ratio); + // The only device that supports the resolution and aspect ratio constraint + // is the high-res device. The 1920x1080 is the least expensive format. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(1920, result.settings.GetWidth()); + EXPECT_EQ(1080, result.settings.GetHeight()); + } +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, IdealAspectRatio) { + constraint_factory_.Reset(); + { + const double kIdealAspectRatio = 0.5; + constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + double min_width = 1.0; + double max_width = result.settings.GetWidth(); + double min_height = 1.0; + double max_height = result.settings.GetHeight(); + double min_aspect_ratio = min_width / max_height; + double max_aspect_ratio = max_width / min_height; + // All devices in |capabilities_| support the ideal aspect-ratio. + // The algorithm should prefer the default device with closest-to-default + // settings. + EXPECT_LE(kIdealAspectRatio, max_aspect_ratio); + EXPECT_GE(kIdealAspectRatio, min_aspect_ratio); + EXPECT_EQ(default_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*default_closest_format_, result.settings.format()); + } + + { + const double kIdealAspectRatio = 1500.0; + constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // The only device that supports the ideal aspect ratio is the high-res + // device. The least expensive way to support it with the 1920x1080 format + // cropped to 1500x1. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(1920, result.settings.GetWidth()); + EXPECT_EQ(1080, result.settings.GetHeight()); + } + + { + const double kIdealAspectRatio = 2000.0; + constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // The only device that supports the ideal aspect ratio is the high-res + // device with its highest resolution, cropped to 2000x1. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*high_res_highest_format_, result.settings.format()); + } + + { + const double kIdealAspectRatio = 4000.0; + constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // The configuration closest to the ideal aspect ratio is is the high-res + // device with its highest resolution, cropped to 2304x1. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*high_res_highest_format_, result.settings.format()); + } + + { + const double kIdealAspectRatio = 2.0; + constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio); + constraint_factory_.basic().height.setExact(400); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // The first device to support the ideal aspect ratio and the resolution + // constraint is the low-res device. The 800x600 format cropped to 800x400 + // is the lest expensive way to achieve it. + EXPECT_EQ(low_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(800, result.settings.GetWidth()); + EXPECT_EQ(600, result.settings.GetHeight()); + } + + { + const double kIdealAspectRatio = 3.0; + constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio); + constraint_factory_.basic().height.setExact(400); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // The only device that supports the ideal aspect ratio and the resolution + // constraint is the high-res device. The 1280x720 cropped to 1200x400 is + // the lest expensive way to achieve it. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(1280, result.settings.GetWidth()); + EXPECT_EQ(720, result.settings.GetHeight()); + } +} + +// The "Advanced" tests check selection criteria involving advanced constraint +// sets. +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, AdvancedExactResolution) { + { + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + advanced1.width.setExact(4000); + advanced1.height.setExact(4000); + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.width.setExact(3000); + advanced2.height.setExact(3000); + auto result = SelectSettings(); + // No device supports the advanced constraint sets. + // Tie-breaker rule that applies is closeness to default settings. + EXPECT_EQ(default_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*default_closest_format_, result.settings.format()); + + blink::WebMediaTrackConstraintSet& advanced3 = + constraint_factory_.AddAdvanced(); + advanced3.width.setExact(1920); + advanced3.height.setExact(1080); + result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // The high-res device natively supports the third advanced constraint set + // and should be selected. + // First tie-breaker rule that applies is support for advanced constraints + // that appear first. Second tie-breaker rule is custom distance to advanced + // constraint sets that appear first. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(1920, result.settings.GetWidth()); + EXPECT_EQ(1080, result.settings.GetHeight()); + + blink::WebMediaTrackConstraintSet& advanced4 = + constraint_factory_.AddAdvanced(); + advanced4.width.setExact(640); + advanced4.height.setExact(480); + result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // First tie-breaker rule that applies is support for advanced constraints + // that appear first, which leaves out configurations that only support the + // fourth advanced constraint set in favor of configurations that support + // the third set. + // Second tie-breaker rule is custom distance to advanced constraint sets + // that appear first. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(1920, result.settings.GetWidth()); + EXPECT_EQ(1080, result.settings.GetHeight()); + + constraint_factory_.basic().width.setIdeal(800); + constraint_factory_.basic().height.setIdeal(600); + result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // The ideal value is supported by the same configuration, so nothing + // changes. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(1920, result.settings.GetWidth()); + EXPECT_EQ(1080, result.settings.GetHeight()); + + constraint_factory_.basic().width.setIdeal(2000); + constraint_factory_.basic().height.setIdeal(1500); + result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // The closest configuration to the ideal resolution is the high-res device + // at the highest resolution. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(*high_res_highest_format_, result.settings.format()); + } +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, + AdvancedResolutionAndFrameRate) { + { + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + advanced1.width.setExact(1920); + advanced1.height.setExact(1080); + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.frameRate.setExact(60.0); + blink::WebMediaTrackConstraintSet& advanced3 = + constraint_factory_.AddAdvanced(); + advanced3.width.setExact(2304); + advanced3.height.setExact(1536); + auto result = SelectSettings(); + EXPECT_TRUE(result.has_value()); + // The high-res device is the only one that satisfies the first advanced + // set. 2304x1536x10.0 satisfies sets 1 and 3, while 1920x1080x60.0 + // satisfies sets 1, and 2. The latter must be selected, regardless of + // any other criteria. + EXPECT_EQ(high_res_device_->device_id, result.settings.device_id()); + EXPECT_EQ(1920, result.settings.GetWidth()); + EXPECT_EQ(1080, result.settings.GetHeight()); + EXPECT_EQ(60.0, result.settings.GetFrameRate()); + } +} + +// The "NoDevices" tests verify that the algorithm returns the expected result +// when there are no candidates to choose from. +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, NoDevicesNoConstraints) { + constraint_factory_.Reset(); + VideoCaptureCapabilities capabilities; + auto result = SelectVideoCaptureSourceSettings( + capabilities, constraint_factory_.CreateWebMediaConstraints()); + EXPECT_FALSE(result.has_value()); + EXPECT_TRUE(std::string(result.failed_constraint_name).empty()); +} + +TEST_F(MediaStreamConstraintsUtilVideoSourceTest, NoDevicesWithConstraints) { + constraint_factory_.Reset(); + constraint_factory_.basic().height.setExact(100); + VideoCaptureCapabilities capabilities; + auto result = SelectVideoCaptureSourceSettings( + capabilities, constraint_factory_.CreateWebMediaConstraints()); + EXPECT_FALSE(result.has_value()); + EXPECT_TRUE(std::string(result.failed_constraint_name).empty()); +} + +} // namespace content
diff --git a/content/renderer/media/recorder/OWNERS b/content/renderer/media/recorder/OWNERS new file mode 100644 index 0000000..687c6bd --- /dev/null +++ b/content/renderer/media/recorder/OWNERS
@@ -0,0 +1,4 @@ +emircan@chromium.org +mcasas@chromium.org + +# COMPONENT: Blink>MediaRecording
diff --git a/content/renderer/media/audio_track_recorder.cc b/content/renderer/media/recorder/audio_track_recorder.cc similarity index 99% rename from content/renderer/media/audio_track_recorder.cc rename to content/renderer/media/recorder/audio_track_recorder.cc index 80df037..874c78c 100644 --- a/content/renderer/media/audio_track_recorder.cc +++ b/content/renderer/media/recorder/audio_track_recorder.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/renderer/media/audio_track_recorder.h" +#include "content/renderer/media/recorder/audio_track_recorder.h" #include <stdint.h> #include <utility>
diff --git a/content/renderer/media/audio_track_recorder.h b/content/renderer/media/recorder/audio_track_recorder.h similarity index 93% rename from content/renderer/media/audio_track_recorder.h rename to content/renderer/media/recorder/audio_track_recorder.h index 15eb3cb..1b9554a 100644 --- a/content/renderer/media/audio_track_recorder.h +++ b/content/renderer/media/recorder/audio_track_recorder.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_RENDERER_MEDIA_AUDIO_TRACK_RECORDER_H_ -#define CONTENT_RENDERER_MEDIA_AUDIO_TRACK_RECORDER_H_ +#ifndef CONTENT_RENDERER_MEDIA_RECORDER_AUDIO_TRACK_RECORDER_H_ +#define CONTENT_RENDERER_MEDIA_RECORDER_AUDIO_TRACK_RECORDER_H_ #include <memory> @@ -81,4 +81,4 @@ } // namespace content -#endif // CONTENT_RENDERER_MEDIA_AUDIO_TRACK_RECORDER_H_ +#endif // CONTENT_RENDERER_MEDIA_RECORDER_AUDIO_TRACK_RECORDER_H_
diff --git a/content/renderer/media/audio_track_recorder_unittest.cc b/content/renderer/media/recorder/audio_track_recorder_unittest.cc similarity index 99% rename from content/renderer/media/audio_track_recorder_unittest.cc rename to content/renderer/media/recorder/audio_track_recorder_unittest.cc index 13cd690..b7c9bea2b 100644 --- a/content/renderer/media/audio_track_recorder_unittest.cc +++ b/content/renderer/media/recorder/audio_track_recorder_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/renderer/media/audio_track_recorder.h" +#include "content/renderer/media/recorder/audio_track_recorder.h" #include <stdint.h>
diff --git a/content/renderer/media/media_recorder_handler.cc b/content/renderer/media/recorder/media_recorder_handler.cc similarity index 98% rename from content/renderer/media/media_recorder_handler.cc rename to content/renderer/media/recorder/media_recorder_handler.cc index d798c82f..3c3d2e8 100644 --- a/content/renderer/media/media_recorder_handler.cc +++ b/content/renderer/media/recorder/media_recorder_handler.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/renderer/media/media_recorder_handler.h" +#include "content/renderer/media/recorder/media_recorder_handler.h" #include <utility> @@ -12,9 +12,9 @@ #include "base/macros.h" #include "base/strings/string_tokenizer.h" #include "base/strings/string_util.h" -#include "content/renderer/media/audio_track_recorder.h" #include "content/renderer/media/media_stream_audio_track.h" #include "content/renderer/media/media_stream_track.h" +#include "content/renderer/media/recorder/audio_track_recorder.h" #include "content/renderer/media/webrtc_uma_histograms.h" #include "media/base/audio_bus.h" #include "media/base/audio_parameters.h"
diff --git a/content/renderer/media/media_recorder_handler.h b/content/renderer/media/recorder/media_recorder_handler.h similarity index 93% rename from content/renderer/media/media_recorder_handler.h rename to content/renderer/media/recorder/media_recorder_handler.h index ab2ec74..58d3d6f 100644 --- a/content/renderer/media/media_recorder_handler.h +++ b/content/renderer/media/recorder/media_recorder_handler.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_RENDERER_MEDIA_MEDIA_RECORDER_HANDLER_H_ -#define CONTENT_RENDERER_MEDIA_MEDIA_RECORDER_HANDLER_H_ +#ifndef CONTENT_RENDERER_MEDIA_RECORDER_MEDIA_RECORDER_HANDLER_H_ +#define CONTENT_RENDERER_MEDIA_RECORDER_MEDIA_RECORDER_HANDLER_H_ #include <memory> @@ -13,7 +13,7 @@ #include "base/strings/string_piece.h" #include "base/threading/thread_checker.h" #include "content/common/content_export.h" -#include "content/renderer/media/video_track_recorder.h" +#include "content/renderer/media/recorder/video_track_recorder.h" #include "third_party/WebKit/public/platform/WebMediaRecorderHandler.h" #include "third_party/WebKit/public/platform/WebMediaStream.h" @@ -114,4 +114,4 @@ }; } // namespace content -#endif // CONTENT_RENDERER_MEDIA_MEDIA_RECORDER_HANDLER_H_ +#endif // CONTENT_RENDERER_MEDIA_RECORDER_MEDIA_RECORDER_HANDLER_H_
diff --git a/content/renderer/media/media_recorder_handler_unittest.cc b/content/renderer/media/recorder/media_recorder_handler_unittest.cc similarity index 99% rename from content/renderer/media/media_recorder_handler_unittest.cc rename to content/renderer/media/recorder/media_recorder_handler_unittest.cc index 9903f1b..fa90e65b 100644 --- a/content/renderer/media/media_recorder_handler_unittest.cc +++ b/content/renderer/media/recorder/media_recorder_handler_unittest.cc
@@ -11,8 +11,8 @@ #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "content/child/child_process.h" -#include "content/renderer/media/media_recorder_handler.h" #include "content/renderer/media/mock_media_stream_registry.h" +#include "content/renderer/media/recorder/media_recorder_handler.h" #include "media/audio/simple_sources.h" #include "media/base/audio_bus.h" #include "media/base/video_frame.h"
diff --git a/content/renderer/media/video_track_recorder.cc b/content/renderer/media/recorder/video_track_recorder.cc similarity index 99% rename from content/renderer/media/video_track_recorder.cc rename to content/renderer/media/recorder/video_track_recorder.cc index c92c7b6..a066adb 100644 --- a/content/renderer/media/video_track_recorder.cc +++ b/content/renderer/media/recorder/video_track_recorder.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/renderer/media/video_track_recorder.h" +#include "content/renderer/media/recorder/video_track_recorder.h" #include <utility>
diff --git a/content/renderer/media/video_track_recorder.h b/content/renderer/media/recorder/video_track_recorder.h similarity index 94% rename from content/renderer/media/video_track_recorder.h rename to content/renderer/media/recorder/video_track_recorder.h index 0460cfa..895523d 100644 --- a/content/renderer/media/video_track_recorder.h +++ b/content/renderer/media/recorder/video_track_recorder.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_RENDERER_MEDIA_VIDEO_TRACK_RECORDER_H_ -#define CONTENT_RENDERER_MEDIA_VIDEO_TRACK_RECORDER_H_ +#ifndef CONTENT_RENDERER_MEDIA_RECORDER_VIDEO_TRACK_RECORDER_H_ +#define CONTENT_RENDERER_MEDIA_RECORDER_VIDEO_TRACK_RECORDER_H_ #include <memory> @@ -98,4 +98,4 @@ }; } // namespace content -#endif // CONTENT_RENDERER_MEDIA_VIDEO_TRACK_RECORDER_H_ +#endif // CONTENT_RENDERER_MEDIA_RECORDER_VIDEO_TRACK_RECORDER_H_
diff --git a/content/renderer/media/video_track_recorder_unittest.cc b/content/renderer/media/recorder/video_track_recorder_unittest.cc similarity index 98% rename from content/renderer/media/video_track_recorder_unittest.cc rename to content/renderer/media/recorder/video_track_recorder_unittest.cc index 97bfa40..3eb455e 100644 --- a/content/renderer/media/video_track_recorder_unittest.cc +++ b/content/renderer/media/recorder/video_track_recorder_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/renderer/media/video_track_recorder.h" +#include "content/renderer/media/recorder/video_track_recorder.h" #include <stddef.h>
diff --git a/content/renderer/media/render_media_log.cc b/content/renderer/media/render_media_log.cc index 1169f685..059e68b 100644 --- a/content/renderer/media/render_media_log.cc +++ b/content/renderer/media/render_media_log.cc
@@ -42,9 +42,11 @@ namespace content { -RenderMediaLog::RenderMediaLog(const GURL& security_origin) +RenderMediaLog::RenderMediaLog( + const GURL& security_origin, + scoped_refptr<base::SingleThreadTaskRunner> task_runner) : security_origin_(security_origin), - task_runner_(base::ThreadTaskRunnerHandle::Get()), + task_runner_(task_runner), tick_clock_(new base::DefaultTickClock()), last_ipc_send_time_(tick_clock_->NowTicks()), ipc_send_pending_(false) {
diff --git a/content/renderer/media/render_media_log.h b/content/renderer/media/render_media_log.h index ed9ce62..568e283 100644 --- a/content/renderer/media/render_media_log.h +++ b/content/renderer/media/render_media_log.h
@@ -33,7 +33,9 @@ // It must be constructed on the render thread. class CONTENT_EXPORT RenderMediaLog : public media::MediaLog { public: - explicit RenderMediaLog(const GURL& security_origin); + explicit RenderMediaLog( + const GURL& security_origin, + scoped_refptr<base::SingleThreadTaskRunner> task_runner); // MediaLog implementation. void AddEvent(std::unique_ptr<media::MediaLogEvent> event) override;
diff --git a/content/renderer/media/render_media_log_unittest.cc b/content/renderer/media/render_media_log_unittest.cc index 905bec5..a4633c2 100644 --- a/content/renderer/media/render_media_log_unittest.cc +++ b/content/renderer/media/render_media_log_unittest.cc
@@ -8,6 +8,7 @@ #include "base/message_loop/message_loop.h" #include "base/test/simple_test_tick_clock.h" #include "base/test/test_mock_time_task_runner.h" +#include "base/threading/thread_task_runner_handle.h" #include "content/common/view_messages.h" #include "content/public/test/mock_render_thread.h" #include "content/renderer/media/render_media_log.h" @@ -18,7 +19,8 @@ class RenderMediaLogTest : public testing::Test { public: RenderMediaLogTest() - : log_(new RenderMediaLog(GURL("http://foo.com"))), + : log_(new RenderMediaLog(GURL("http://foo.com"), + base::ThreadTaskRunnerHandle::Get())), tick_clock_(new base::SimpleTestTickClock()), task_runner_(new base::TestMockTimeTaskRunner()) { log_->SetTickClockForTesting(std::unique_ptr<base::TickClock>(tick_clock_));
diff --git a/content/renderer/presentation/presentation_connection_proxy_unittest.cc b/content/renderer/presentation/presentation_connection_proxy_unittest.cc index 1a94178..5e43a224 100644 --- a/content/renderer/presentation/presentation_connection_proxy_unittest.cc +++ b/content/renderer/presentation/presentation_connection_proxy_unittest.cc
@@ -10,6 +10,7 @@ #include "content/renderer/presentation/presentation_connection_proxy.h" #include "content/renderer/presentation/test_presentation_connection.h" #include "testing/gmock/include/gmock/gmock.h" +#include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/modules/presentation/WebPresentationConnection.h" #include "third_party/WebKit/public/platform/modules/presentation/WebPresentationController.h"
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 1876c41..abfcafa4 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -618,7 +618,8 @@ // PlzNavigate CommonNavigationParams MakeCommonNavigationParams( - const blink::WebFrameClient::NavigationPolicyInfo& info) { + const blink::WebFrameClient::NavigationPolicyInfo& info, + int load_flags) { Referrer referrer( GURL(info.urlRequest.httpHeaderField( WebString::fromUTF8("Referer")).latin1()), @@ -637,10 +638,15 @@ static_cast<FrameMsg_UILoadMetricsReportType::Value>( info.urlRequest.inputPerfMetricReportPolicy()); + // Determine the navigation type. FrameMsg_Navigate_Type::Value navigation_type = - info.navigationType == blink::WebNavigationTypeReload - ? FrameMsg_Navigate_Type::RELOAD - : FrameMsg_Navigate_Type::NORMAL; + FrameMsg_Navigate_Type::NORMAL; + if (info.navigationType == blink::WebNavigationTypeReload) { + if (load_flags & net::LOAD_BYPASS_CACHE) + navigation_type = FrameMsg_Navigate_Type::RELOAD_BYPASSING_CACHE; + else + navigation_type = FrameMsg_Navigate_Type::RELOAD; + } const RequestExtraData* extra_data = static_cast<RequestExtraData*>(info.urlRequest.getExtraData()); @@ -1561,6 +1567,7 @@ OnSetAccessibilityMode) IPC_MESSAGE_HANDLER(AccessibilityMsg_SnapshotTree, OnSnapshotAccessibilityTree) + IPC_MESSAGE_HANDLER(FrameMsg_ExtractSmartClipData, OnExtractSmartClipData) IPC_MESSAGE_HANDLER(FrameMsg_UpdateOpener, OnUpdateOpener) IPC_MESSAGE_HANDLER(FrameMsg_CommitNavigation, OnCommitNavigation) IPC_MESSAGE_HANDLER(FrameMsg_DidUpdateSandboxFlags, OnDidUpdateSandboxFlags) @@ -2139,6 +2146,15 @@ routing_id_, callback_id, response)); } +void RenderFrameImpl::OnExtractSmartClipData(uint32_t id, + const gfx::Rect& rect) { + blink::WebString clip_text; + blink::WebString clip_html; + GetWebFrame()->extractSmartClipData(rect, clip_text, clip_html); + Send(new FrameHostMsg_SmartClipDataExtracted( + routing_id_, id, clip_text.utf16(), clip_html.utf16())); +} + void RenderFrameImpl::OnUpdateOpener(int opener_routing_id) { WebFrame* opener = ResolveOpener(opener_routing_id); frame_->setOpener(opener); @@ -2814,7 +2830,8 @@ RenderThreadImpl::current()->SharedMainThreadContextProvider()); scoped_refptr<media::MediaLog> media_log( - new RenderMediaLog(url::Origin(frame_->getSecurityOrigin()).GetURL())); + new RenderMediaLog(url::Origin(frame_->getSecurityOrigin()).GetURL(), + frame_->timerTaskRunner())); #if defined(OS_ANDROID) if (UseWebMediaPlayerImpl(url) && !media_surface_manager_) @@ -3442,27 +3459,25 @@ content_initiated)); } -void RenderFrameImpl::didStartProvisionalLoad(blink::WebLocalFrame* frame) { - DCHECK_EQ(frame_, frame); - WebDataSource* ds = frame->provisionalDataSource(); - +void RenderFrameImpl::didStartProvisionalLoad( + blink::WebDataSource* data_source) { // In fast/loader/stop-provisional-loads.html, we abort the load before this // callback is invoked. - if (!ds) + if (!data_source) return; TRACE_EVENT2("navigation,benchmark,rail", "RenderFrameImpl::didStartProvisionalLoad", "id", routing_id_, - "url", ds->getRequest().url().string().utf8()); - DocumentState* document_state = DocumentState::FromDataSource(ds); + "url", data_source->getRequest().url().string().utf8()); + DocumentState* document_state = DocumentState::FromDataSource(data_source); NavigationStateImpl* navigation_state = static_cast<NavigationStateImpl*>( document_state->navigation_state()); - bool is_top_most = !frame->parent(); + bool is_top_most = !frame_->parent(); if (is_top_most) { render_view_->set_navigation_gesture( WebUserGestureIndicator::isProcessingUserGesture() ? NavigationGestureUser : NavigationGestureAuto); - } else if (ds->replacesCurrentHistoryItem()) { + } else if (data_source->replacesCurrentHistoryItem()) { // Subframe navigations that don't add session history items must be // marked with AUTO_SUBFRAME. See also didFailProvisionalLoad for how we // handle loading of error pages. @@ -3474,15 +3489,16 @@ DCHECK(!navigation_start.is_null()); for (auto& observer : render_view_->observers()) - observer.DidStartProvisionalLoad(frame); + observer.DidStartProvisionalLoad(frame_); for (auto& observer : observers_) - observer.DidStartProvisionalLoad(); + observer.DidStartProvisionalLoad(data_source); std::vector<GURL> redirect_chain; - GetRedirectChain(ds, &redirect_chain); - CHECK(!redirect_chain.empty()); + GetRedirectChain(data_source, &redirect_chain); + Send(new FrameHostMsg_DidStartProvisionalLoad( - routing_id_, ds->getRequest().url(), redirect_chain, navigation_start)); + routing_id_, data_source->getRequest().url(), redirect_chain, + navigation_start)); } void RenderFrameImpl::didReceiveServerRedirectForProvisionalLoad( @@ -6134,7 +6150,8 @@ return new WebMediaPlayerMS( frame_, client, GetWebMediaPlayerDelegate(), - new RenderMediaLog(url::Origin(security_origin).GetURL()), + new RenderMediaLog(url::Origin(security_origin).GetURL(), + frame_->timerTaskRunner()), CreateRendererFactory(), render_thread->GetIOTaskRunner(), compositor_task_runner, render_thread->GetMediaThreadTaskRunner(), render_thread->GetWorkerTaskRunner(), render_thread->GetGpuFactories(), @@ -6260,7 +6277,8 @@ begin_navigation_params.client_side_redirect_url = frame_->document().url(); Send(new FrameHostMsg_BeginNavigation( - routing_id_, MakeCommonNavigationParams(info), begin_navigation_params)); + routing_id_, MakeCommonNavigationParams(info, load_flags), + begin_navigation_params)); } void RenderFrameImpl::LoadDataURL(
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index abffd65..3677ee3 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h
@@ -50,6 +50,7 @@ #include "mojo/public/cpp/bindings/associated_binding.h" #include "mojo/public/cpp/bindings/binding.h" #include "ppapi/features/features.h" +#include "services/service_manager/public/cpp/service_info.h" #include "services/service_manager/public/interfaces/connector.mojom.h" #include "services/service_manager/public/interfaces/interface_provider.mojom.h" #include "third_party/WebKit/public/platform/WebEffectiveConnectionType.h" @@ -548,7 +549,7 @@ void willSubmitForm(const blink::WebFormElement& form) override; void didCreateDataSource(blink::WebLocalFrame* frame, blink::WebDataSource* datasource) override; - void didStartProvisionalLoad(blink::WebLocalFrame* frame) override; + void didStartProvisionalLoad(blink::WebDataSource* data_source) override; void didReceiveServerRedirectForProvisionalLoad( blink::WebLocalFrame* frame) override; void didFailProvisionalLoad(blink::WebLocalFrame* frame, @@ -873,6 +874,7 @@ void OnFocusedFormFieldDataRequest(int request_id); void OnSetAccessibilityMode(AccessibilityMode new_mode); void OnSnapshotAccessibilityTree(int callback_id); + void OnExtractSmartClipData(uint32_t callback_id, const gfx::Rect& rect); void OnUpdateOpener(int opener_routing_id); void OnDidUpdateSandboxFlags(blink::WebSandboxFlags flags); void OnSetFrameOwnerProperties(
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index fcd2444..ec7d121d 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -146,6 +146,7 @@ #include "services/ui/public/interfaces/constants.mojom.h" #include "skia/ext/event_tracer_impl.h" #include "skia/ext/skia_memory_dump_provider.h" +#include "third_party/WebKit/public/platform/WebCache.h" #include "third_party/WebKit/public/platform/WebImageGenerator.h" #include "third_party/WebKit/public/platform/WebMemoryCoordinator.h" #include "third_party/WebKit/public/platform/WebString.h" @@ -153,7 +154,6 @@ #include "third_party/WebKit/public/platform/scheduler/child/compositor_worker_scheduler.h" #include "third_party/WebKit/public/platform/scheduler/child/webthread_impl_for_worker_scheduler.h" #include "third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h" -#include "third_party/WebKit/public/web/WebCache.h" #include "third_party/WebKit/public/web/WebDatabase.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebFrame.h" @@ -922,7 +922,7 @@ // it will exit the process before the browser side is ready to exit. if (!base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kSingleProcess)) - _exit(0); + base::Process::TerminateCurrentProcessImmediately(0); } bool RenderThreadImpl::ShouldBeDestroyed() {
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h index 1506ecf..9a4affd 100644 --- a/content/renderer/render_thread_impl.h +++ b/content/renderer/render_thread_impl.h
@@ -71,6 +71,7 @@ namespace cc { class BeginFrameSource; class CompositorFrameSink; +class FrameSinkId; class TaskGraphRunner; }
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 03fabd9..f3b38e8 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -1239,7 +1239,6 @@ #if defined(OS_ANDROID) IPC_MESSAGE_HANDLER(ViewMsg_UpdateBrowserControlsState, OnUpdateBrowserControlsState) - IPC_MESSAGE_HANDLER(ViewMsg_ExtractSmartClipData, OnExtractSmartClipData) #elif defined(OS_MACOSX) IPC_MESSAGE_HANDLER(ViewMsg_GetRenderedText, OnGetRenderedText) @@ -1566,10 +1565,6 @@ observer.OnZoomLevelChanged(); } -void RenderViewImpl::didCancelCompositionOnSelectionChange() { - Send(new InputHostMsg_ImeCancelComposition(GetRoutingID())); -} - void RenderViewImpl::SetValidationMessageDirection( base::string16* wrapped_main_text, blink::WebTextDirection main_text_hint,
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h index 4eb69544..fb347acb 100644 --- a/content/renderer/render_view_impl.h +++ b/content/renderer/render_view_impl.h
@@ -300,7 +300,6 @@ bool enumerateChosenDirectory( const blink::WebString& path, blink::WebFileChooserCompletion* chooser_completion) override; - void didCancelCompositionOnSelectionChange() override; void SetValidationMessageDirection(base::string16* main_text, blink::WebTextDirection main_text_hint, base::string16* sub_text, @@ -563,7 +562,6 @@ void OnUpdateBrowserControlsState(bool enable_hiding, bool enable_showing, bool animate); - void OnExtractSmartClipData(const gfx::Rect& rect); #elif defined(OS_MACOSX) void OnGetRenderedText(); #endif
diff --git a/content/renderer/render_view_impl_android.cc b/content/renderer/render_view_impl_android.cc index e13fea07..aa3d3a1 100644 --- a/content/renderer/render_view_impl_android.cc +++ b/content/renderer/render_view_impl_android.cc
@@ -71,13 +71,4 @@ UpdateBrowserControlsState(top_controls_constraints_, current, true); } -void RenderViewImpl::OnExtractSmartClipData(const gfx::Rect& rect) { - blink::WebString clip_text; - blink::WebString clip_html; - blink::WebRect clip_rect; - webview()->extractSmartClipData(rect, clip_text, clip_html, clip_rect); - Send(new ViewHostMsg_SmartClipDataExtracted(routing_id_, clip_text.utf16(), - clip_html.utf16(), clip_rect)); -} - } // namespace content
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc index 638f383..268f83d 100644 --- a/content/renderer/render_widget.cc +++ b/content/renderer/render_widget.cc
@@ -237,7 +237,7 @@ // These fields are currently unused when dragging into WebKit. DCHECK(drop_data.download_metadata.empty()); DCHECK(drop_data.file_contents.empty()); - DCHECK(drop_data.file_description_filename.empty()); + DCHECK(drop_data.file_contents_content_disposition.empty()); if (!drop_data.text.is_null()) { WebDragData::Item item; @@ -1733,11 +1733,14 @@ Send(new DragHostMsg_UpdateDragCursor(routing_id(), operation)); } -void RenderWidget::OnDragTargetDragLeave() { +void RenderWidget::OnDragTargetDragLeave(const gfx::Point& client_point, + const gfx::Point& screen_point) { if (!GetWebWidget()) return; DCHECK(GetWebWidget()->isWebFrameWidget()); - static_cast<WebFrameWidget*>(GetWebWidget())->dragTargetDragLeave(); + static_cast<WebFrameWidget*>(GetWebWidget()) + ->dragTargetDragLeave(ConvertWindowPointToViewport(client_point), + screen_point); } void RenderWidget::OnDragTargetDrop(const DropData& drop_data,
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h index fde0e32..c40009f 100644 --- a/content/renderer/render_widget.h +++ b/content/renderer/render_widget.h
@@ -527,7 +527,8 @@ const gfx::Point& screen_pt, blink::WebDragOperationsMask operations_allowed, int key_modifiers); - void OnDragTargetDragLeave(); + void OnDragTargetDragLeave(const gfx::Point& client_point, + const gfx::Point& screen_point); void OnDragTargetDrop(const DropData& drop_data, const gfx::Point& client_pt, const gfx::Point& screen_pt,
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc index ac5c05a3..75bda7c 100644 --- a/content/renderer/renderer_blink_platform_impl.cc +++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -55,11 +55,11 @@ #include "content/renderer/gamepad_shared_memory_reader.h" #include "content/renderer/media/audio_decoder.h" #include "content/renderer/media/audio_device_factory.h" -#include "content/renderer/media/canvas_capture_handler.h" -#include "content/renderer/media/html_audio_element_capturer_source.h" -#include "content/renderer/media/html_video_element_capturer_source.h" +#include "content/renderer/media/capturefromelement/canvas_capture_handler.h" +#include "content/renderer/media/capturefromelement/html_audio_element_capturer_source.h" +#include "content/renderer/media/capturefromelement/html_video_element_capturer_source.h" #include "content/renderer/media/image_capture_frame_grabber.h" -#include "content/renderer/media/media_recorder_handler.h" +#include "content/renderer/media/recorder/media_recorder_handler.h" #include "content/renderer/media/renderer_webaudiodevice_impl.h" #include "content/renderer/media/renderer_webmidiaccessor_impl.h" #include "content/renderer/mojo/blink_interface_provider_impl.h"
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc index b07de5d4..8a68da7a 100644 --- a/content/renderer/service_worker/service_worker_context_client.cc +++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -38,6 +38,7 @@ #include "content/common/service_worker/service_worker_event_dispatcher.mojom.h" #include "content/common/service_worker/service_worker_messages.h" #include "content/common/service_worker/service_worker_status_code.h" +#include "content/common/service_worker/service_worker_type_converters.h" #include "content/common/service_worker/service_worker_utils.h" #include "content/public/common/push_event_payload.h" #include "content/public/common/referrer.h" @@ -58,6 +59,7 @@ #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/WebURLResponse.h" #include "third_party/WebKit/public/platform/modules/notifications/WebNotificationData.h" +#include "third_party/WebKit/public/platform/modules/payments/WebPaymentAppRequest.h" #include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerClientQueryOptions.h" #include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerError.h" #include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerRequest.h" @@ -204,6 +206,8 @@ using SkipWaitingCallbacksMap = IDMap<std::unique_ptr<blink::WebServiceWorkerSkipWaitingCallbacks>>; using SyncEventCallbacksMap = IDMap<std::unique_ptr<const SyncCallback>>; + using PaymentRequestEventCallbacksMap = + IDMap<std::unique_ptr<const PaymentRequestEventCallback>>; using PushEventCallbacksMap = IDMap<std::unique_ptr<const DispatchPushEventCallback>>; using FetchEventCallbacksMap = IDMap<std::unique_ptr<const FetchCallback>>; @@ -238,6 +242,9 @@ // Pending callbacks for Background Sync Events. SyncEventCallbacksMap sync_event_callbacks; + // Pending callbacks for Payment Request Events. + PaymentRequestEventCallbacksMap payment_request_event_callbacks; + // Pending callbacks for Push Events. PushEventCallbacksMap push_event_callbacks; @@ -755,6 +762,18 @@ context_->sync_event_callbacks.Remove(request_id); } +void ServiceWorkerContextClient::didHandlePaymentRequestEvent( + int request_id, + blink::WebServiceWorkerEventResult result, + double event_dispatch_time) { + const PaymentRequestEventCallback* callback = + context_->payment_request_event_callbacks.Lookup(request_id); + DCHECK(callback); + callback->Run(EventResultToStatus(result), + base::Time::FromDoubleT(event_dispatch_time)); + context_->payment_request_event_callbacks.Remove(request_id); +} + blink::WebServiceWorkerNetworkProvider* ServiceWorkerContextClient::createServiceWorkerNetworkProvider( blink::WebDataSource* data_source) { @@ -873,7 +892,11 @@ void ServiceWorkerContextClient::DispatchPaymentRequestEvent( payments::mojom::PaymentAppRequestPtr app_request, const DispatchPaymentRequestEventCallback& callback) { - NOTIMPLEMENTED(); + int request_id = context_->payment_request_event_callbacks.Add( + base::MakeUnique<PaymentRequestEventCallback>(callback)); + blink::WebPaymentAppRequest webAppRequest = + mojo::ConvertTo<blink::WebPaymentAppRequest>(std::move(app_request)); + proxy_->dispatchPaymentRequestEvent(request_id, webAppRequest); } void ServiceWorkerContextClient::Send(IPC::Message* message) {
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h index e731f13..360ec52 100644 --- a/content/renderer/service_worker/service_worker_context_client.h +++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -170,6 +170,9 @@ void didHandleSyncEvent(int request_id, blink::WebServiceWorkerEventResult result, double dispatch_event_time) override; + void didHandlePaymentRequestEvent(int request_id, + blink::WebServiceWorkerEventResult result, + double dispatch_event_time) override; // Called on the main thread. blink::WebServiceWorkerNetworkProvider* createServiceWorkerNetworkProvider(
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn index 6749acd..bd3da17 100644 --- a/content/shell/BUILD.gn +++ b/content/shell/BUILD.gn
@@ -164,8 +164,6 @@ "common/shell_origin_trial_policy.h", "common/shell_switches.cc", "common/shell_switches.h", - "common/shell_test_configuration.cc", - "common/shell_test_configuration.h", "renderer/layout_test/blink_test_helpers.cc", "renderer/layout_test/blink_test_helpers.h", "renderer/layout_test/blink_test_runner.cc", @@ -760,6 +758,12 @@ mojom("mojo_bindings") { sources = [ + "common/layout_test.mojom", "common/layout_test/layout_test_bluetooth_fake_adapter_setter.mojom", ] + public_deps = [ + "//mojo/common:common_custom_types", + "//ui/gfx/geometry/mojo", + "//url/mojo:url_mojom_gurl", + ] }
diff --git a/content/shell/OWNERS b/content/shell/OWNERS index fec2591e..eb6d043 100644 --- a/content/shell/OWNERS +++ b/content/shell/OWNERS
@@ -1,2 +1,4 @@ mkwst@chromium.org peter@chromium.org + +# COMPONENT: Test
diff --git a/content/shell/android/browsertests_apk/content_browser_tests_jni_onload.cc b/content/shell/android/browsertests_apk/content_browser_tests_jni_onload.cc index 675d69d..3fcfb1b 100644 --- a/content/shell/android/browsertests_apk/content_browser_tests_jni_onload.cc +++ b/content/shell/android/browsertests_apk/content_browser_tests_jni_onload.cc
@@ -4,6 +4,7 @@ #include "base/android/base_jni_registrar.h" #include "base/android/jni_android.h" +#include "base/android/library_loader/library_loader_hooks.h" #include "base/bind.h" #include "content/public/app/content_jni_onload.h" #include "content/public/app/content_main.h" @@ -13,13 +14,15 @@ namespace { -bool RegisterJNI(JNIEnv* env) { +bool RegisterJNI(JNIEnv *env) { return base::android::RegisterJni(env) && content::android::RegisterShellJni(env) && testing::android::RegisterNativeTestJNI(env); } -bool Init() { +bool NativeInit() { + if (!content::android::OnJNIOnLoadInit()) + return false; content::SetContentMainDelegate(new content::ShellMainDelegate()); return true; } @@ -29,12 +32,10 @@ // This is called by the VM when the shared library is first loaded. JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { - std::vector<base::android::RegisterCallback> register_callbacks; - register_callbacks.push_back(base::Bind(&RegisterJNI)); - std::vector<base::android::InitCallback> init_callbacks; - init_callbacks.push_back(base::Bind(&Init)); - if (!content::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks) || - !content::android::OnJNIOnLoadInit(init_callbacks)) { + base::android::InitVM(vm); + JNIEnv* env = base::android::AttachCurrentThread(); + if (!content::android::OnJNIOnLoadRegisterJNI(env) || !RegisterJNI(env) || + !NativeInit()) { return -1; } return JNI_VERSION_1_4;
diff --git a/content/shell/android/linker_test_apk/chromium_linker_test_android.cc b/content/shell/android/linker_test_apk/chromium_linker_test_android.cc index 82e161f7..19f9c47 100644 --- a/content/shell/android/linker_test_apk/chromium_linker_test_android.cc +++ b/content/shell/android/linker_test_apk/chromium_linker_test_android.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/android/jni_android.h" +#include "base/android/library_loader/library_loader_hooks.h" #include "base/bind.h" #include "content/public/app/content_jni_onload.h" #include "content/public/app/content_main.h" @@ -25,7 +26,9 @@ return true; } -bool Init() { +bool NativeInit() { + if (!content::android::OnJNIOnLoadInit()) + return false; content::Compositor::Initialize(); content::SetContentMainDelegate(new content::ShellMainDelegate()); return true; @@ -35,12 +38,10 @@ // This is called by the VM when the shared library is first loaded. JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { - std::vector<base::android::RegisterCallback> register_callbacks; - register_callbacks.push_back(base::Bind(&RegisterJNI)); - std::vector<base::android::InitCallback> init_callbacks; - init_callbacks.push_back(base::Bind(&Init)); - if (!content::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks) || - !content::android::OnJNIOnLoadInit(init_callbacks)) { + base::android::InitVM(vm); + JNIEnv* env = base::android::AttachCurrentThread(); + if (!content::android::OnJNIOnLoadRegisterJNI(env) || !RegisterJNI(env) || + !NativeInit()) { return -1; } return JNI_VERSION_1_4;
diff --git a/content/shell/android/shell_library_loader.cc b/content/shell/android/shell_library_loader.cc index d9b3d28b..dc88bd67 100644 --- a/content/shell/android/shell_library_loader.cc +++ b/content/shell/android/shell_library_loader.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/android/jni_android.h" +#include "base/android/library_loader/library_loader_hooks.h" #include "base/bind.h" #include "content/public/app/content_jni_onload.h" #include "content/public/app/content_main.h" @@ -16,7 +17,10 @@ return content::android::RegisterShellJni(env); } -bool Init() { +bool NativeInit() { + if (!content::android::OnJNIOnLoadInit()) + return false; + content::Compositor::Initialize(); content::SetContentMainDelegate(new content::ShellMainDelegate()); return true; @@ -27,12 +31,10 @@ // This is called by the VM when the shared library is first loaded. JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { - std::vector<base::android::RegisterCallback> register_callbacks; - register_callbacks.push_back(base::Bind(&RegisterJNI)); - std::vector<base::android::InitCallback> init_callbacks; - init_callbacks.push_back(base::Bind(&Init)); - if (!content::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks) || - !content::android::OnJNIOnLoadInit(init_callbacks)) { + base::android::InitVM(vm); + JNIEnv* env = base::android::AttachCurrentThread(); + if (!content::android::OnJNIOnLoadRegisterJNI(env) || !RegisterJNI(env) || + !NativeInit()) { return -1; } return JNI_VERSION_1_4;
diff --git a/content/shell/browser/content_shell_renderer_manifest_overlay.json b/content/shell/browser/content_shell_renderer_manifest_overlay.json index ec29032..2d373b4 100644 --- a/content/shell/browser/content_shell_renderer_manifest_overlay.json +++ b/content/shell/browser/content_shell_renderer_manifest_overlay.json
@@ -7,6 +7,13 @@ "content::mojom::TestService" ] } + }, + "navigation:frame": { + "provides": { + "browser": [ + "content::mojom::LayoutTestControl" + ] + } } } }
diff --git a/content/shell/browser/layout_test/blink_test_controller.cc b/content/shell/browser/layout_test/blink_test_controller.cc index 9273add..892d239 100644 --- a/content/shell/browser/layout_test/blink_test_controller.cc +++ b/content/shell/browser/layout_test/blink_test_controller.cc
@@ -38,6 +38,7 @@ #include "content/public/browser/service_worker_context.h" #include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/associated_interface_provider.h" #include "content/public/common/bindings_policy.h" #include "content/public/common/content_switches.h" #include "content/public/common/url_constants.h" @@ -280,6 +281,7 @@ all_observed_render_process_hosts_.clear(); main_window_render_process_hosts_.clear(); accumulated_layout_test_runtime_flags_changes_.Clear(); + layout_test_control_map_.clear(); ShellBrowserContext* browser_context = ShellContentBrowserClient::Get()->browser_context(); is_compositing_test_ = @@ -605,24 +607,25 @@ // Make sure the new renderer process has a test configuration shared with // other renderers. - ShellTestConfiguration params; - params.current_working_directory = current_working_directory_; - params.temp_path = temp_path_; - params.test_url = test_url_; - params.enable_pixel_dumping = enable_pixel_dumping_; - params.allow_external_pages = + mojom::ShellTestConfigurationPtr params = + mojom::ShellTestConfiguration::New(); + params->allow_external_pages = false; + params->current_working_directory = current_working_directory_; + params->temp_path = temp_path_; + params->test_url = test_url_; + params->enable_pixel_dumping = enable_pixel_dumping_; + params->allow_external_pages = base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kAllowExternalPages); - params.expected_pixel_hash = expected_pixel_hash_; - params.initial_size = initial_size_; + params->expected_pixel_hash = expected_pixel_hash_; + params->initial_size = initial_size_; if (did_send_initial_test_configuration_) { - frame->Send(new ShellViewMsg_ReplicateTestConfiguration( - frame->GetRoutingID(), params)); + GetLayoutTestControlPtr(frame)->ReplicateTestConfiguration( + std::move(params)); } else { did_send_initial_test_configuration_ = true; - frame->Send( - new ShellViewMsg_SetTestConfiguration(frame->GetRoutingID(), params)); + GetLayoutTestControlPtr(frame)->SetTestConfiguration(std::move(params)); } } @@ -632,8 +635,7 @@ all_observed_render_process_hosts_.insert(process); if (!main_window) { - frame->Send( - new ShellViewMsg_SetupSecondaryRenderer(frame->GetRoutingID())); + GetLayoutTestControlPtr(frame)->SetupSecondaryRenderer(); } process->Send(new LayoutTestMsg_ReplicateLayoutTestRuntimeFlagsChanges( @@ -704,8 +706,16 @@ } void BlinkTestController::OnInitiateLayoutDump() { - pending_layout_dumps_ = main_window_->web_contents()->SendToAllFrames( - new ShellViewMsg_LayoutDumpRequest(MSG_ROUTING_NONE)); + int number_of_messages = 0; + for (RenderFrameHost* rfh : main_window_->web_contents()->GetAllFrames()) { + if (!rfh->IsRenderFrameLive()) + continue; + + ++number_of_messages; + GetLayoutTestControlPtr(rfh)->LayoutDumpRequest(); + } + + pending_layout_dumps_ = number_of_messages; } void BlinkTestController::OnLayoutTestRuntimeFlagsChanged( @@ -953,4 +963,21 @@ bluetooth_chooser_factory_->SendEvent(event, argument); } +mojom::LayoutTestControl* BlinkTestController::GetLayoutTestControlPtr( + RenderFrameHost* frame) { + if (layout_test_control_map_.find(frame) == layout_test_control_map_.end()) { + frame->GetRemoteAssociatedInterfaces()->GetInterface( + &layout_test_control_map_[frame]); + layout_test_control_map_[frame].set_connection_error_handler( + base::Bind(&BlinkTestController::HandleLayoutTestControlError, + base::Unretained(this), frame)); + } + DCHECK(layout_test_control_map_[frame].get()); + return layout_test_control_map_[frame].get(); +} + +void BlinkTestController::HandleLayoutTestControlError(RenderFrameHost* frame) { + layout_test_control_map_.erase(frame); +} + } // namespace content
diff --git a/content/shell/browser/layout_test/blink_test_controller.h b/content/shell/browser/layout_test/blink_test_controller.h index 2d7f699..45fb889 100644 --- a/content/shell/browser/layout_test/blink_test_controller.h +++ b/content/shell/browser/layout_test/blink_test_controller.h
@@ -26,6 +26,7 @@ #include "content/public/browser/render_process_host_observer.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/common/web_preferences.h" +#include "content/shell/common/layout_test.mojom.h" #include "content/shell/common/leak_detection_result.h" #include "ui/gfx/geometry/size.h" @@ -215,6 +216,8 @@ void OnGetBluetoothManualChooserEvents(); void OnSendBluetoothManualChooserEvent(const std::string& event, const std::string& argument); + mojom::LayoutTestControl* GetLayoutTestControlPtr(RenderFrameHost* frame); + void HandleLayoutTestControlError(RenderFrameHost* frame); std::unique_ptr<BlinkTestResultPrinter> printer_; @@ -278,6 +281,9 @@ // renderer created while test is in progress). base::DictionaryValue accumulated_layout_test_runtime_flags_changes_; + // Map from one frame to one mojo pipe. + std::map<RenderFrameHost*, mojom::LayoutTestControlAssociatedPtr> + layout_test_control_map_; #if defined(OS_ANDROID) // Because of the nested message pump implementation, Android needs to allow // waiting on the UI thread while layout tests are being ran.
diff --git a/content/shell/browser/layout_test/layout_test_message_filter.h b/content/shell/browser/layout_test/layout_test_message_filter.h index 1b8829a..c66a46cb 100644 --- a/content/shell/browser/layout_test/layout_test_message_filter.h +++ b/content/shell/browser/layout_test/layout_test_message_filter.h
@@ -17,6 +17,7 @@ namespace base { class DictionaryValue; +class NullableString16; } namespace net {
diff --git a/content/shell/browser/layout_test/layout_test_notification_manager.h b/content/shell/browser/layout_test/layout_test_notification_manager.h index b7108d1..25ce88f 100644 --- a/content/shell/browser/layout_test/layout_test_notification_manager.h +++ b/content/shell/browser/layout_test/layout_test_notification_manager.h
@@ -16,6 +16,10 @@ #include "third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h" #include "url/gurl.h" +namespace base { +class NullableString16; +} + namespace content { class DesktopNotificationDelegate;
diff --git a/content/shell/browser/shell_url_request_context_getter.cc b/content/shell/browser/shell_url_request_context_getter.cc index 1943e4fe..6ee164f 100644 --- a/content/shell/browser/shell_url_request_context_getter.cc +++ b/content/shell/browser/shell_url_request_context_getter.cc
@@ -219,7 +219,7 @@ base::MakeUnique<net::HttpNetworkSession>(network_session_params)); storage_->set_http_transaction_factory(base::MakeUnique<net::HttpCache>( storage_->http_network_session(), std::move(main_backend), - true /* set_up_quic_server_info */)); + true /* is_main_cache */)); std::unique_ptr<net::URLRequestJobFactoryImpl> job_factory( new net::URLRequestJobFactoryImpl());
diff --git a/content/shell/common/OWNERS b/content/shell/common/OWNERS index 42444bc..b6ba3c9 100644 --- a/content/shell/common/OWNERS +++ b/content/shell/common/OWNERS
@@ -1,2 +1,8 @@ per-file *_messages*.h=set noparent per-file *_messages*.h=file://ipc/SECURITY_OWNERS +per-file *.mojom=set noparent +per-file *.mojom=file://ipc/SECURITY_OWNERS +per-file *_messages.cc=set noparent +per-file *_messages.cc=file://ipc/SECURITY_OWNERS +per-file *_param_traits*.*=set noparent +per-file *_param_traits*.*=file://ipc/SECURITY_OWNERS \ No newline at end of file
diff --git a/content/shell/common/layout_test.mojom b/content/shell/common/layout_test.mojom new file mode 100644 index 0000000..c0de4b5 --- /dev/null +++ b/content/shell/common/layout_test.mojom
@@ -0,0 +1,50 @@ +// 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. + +module content.mojom; + +import "mojo/common/file_path.mojom"; +import "ui/gfx/geometry/mojo/geometry.mojom"; +import "url/mojo/url.mojom"; + +struct ShellTestConfiguration { + // The current working directory. + mojo.common.mojom.FilePath current_working_directory; + + // The temporary directory of the system. + mojo.common.mojom.FilePath temp_path; + + // The URL of the current layout test. + url.mojom.Url test_url; + + // True if pixel tests are enabled. + bool enable_pixel_dumping; + + // True if tests can open external URLs + bool allow_external_pages; + + // The expected MD5 hash of the pixel results. + string expected_pixel_hash; + + // The initial size of the test window. + gfx.mojom.Size initial_size; +}; + +interface LayoutTestControl { + // Asks a frame to dump its contents into a string and send them back over + // IPC. + LayoutDumpRequest(); + + // Replicates test config (for an already started test) to a new renderer + // that hosts parts of the main test window. + ReplicateTestConfiguration(ShellTestConfiguration config); + + // Sets the test config for a layout test that is being started. This message + // is sent only to a renderer that hosts parts of the main test window. + SetTestConfiguration(ShellTestConfiguration config); + + // Sets up a secondary renderer (renderer that doesn't [yet] host parts of the + // main test window) for a layout test. + SetupSecondaryRenderer(); +};
diff --git a/content/shell/common/shell_messages.h b/content/shell/common/shell_messages.h index ef45330..087def0f8 100644 --- a/content/shell/common/shell_messages.h +++ b/content/shell/common/shell_messages.h
@@ -10,7 +10,6 @@ #include "content/public/common/common_param_traits.h" #include "content/public/common/page_state.h" #include "content/shell/common/leak_detection_result.h" -#include "content/shell/common/shell_test_configuration.h" #include "ipc/ipc_message_macros.h" #include "ipc/ipc_platform_file.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -19,16 +18,6 @@ #define IPC_MESSAGE_START ShellMsgStart -IPC_STRUCT_TRAITS_BEGIN(content::ShellTestConfiguration) -IPC_STRUCT_TRAITS_MEMBER(current_working_directory) -IPC_STRUCT_TRAITS_MEMBER(temp_path) -IPC_STRUCT_TRAITS_MEMBER(test_url) -IPC_STRUCT_TRAITS_MEMBER(enable_pixel_dumping) -IPC_STRUCT_TRAITS_MEMBER(allow_external_pages) -IPC_STRUCT_TRAITS_MEMBER(expected_pixel_hash) -IPC_STRUCT_TRAITS_MEMBER(initial_size) -IPC_STRUCT_TRAITS_END() - // Tells the renderer to reset all test runners. IPC_MESSAGE_ROUTED0(ShellViewMsg_Reset) @@ -36,20 +25,6 @@ IPC_MESSAGE_CONTROL1(ShellViewMsg_SetWebKitSourceDir, base::FilePath /* webkit source dir */) -// Sets the test config for a layout test that is being started. This message -// is sent only to a renderer that hosts parts of the main test window. -IPC_MESSAGE_ROUTED1(ShellViewMsg_SetTestConfiguration, - content::ShellTestConfiguration) - -// Replicates test config (for an already started test) to a new renderer -// that hosts parts of the main test window. -IPC_MESSAGE_ROUTED1(ShellViewMsg_ReplicateTestConfiguration, - content::ShellTestConfiguration) - -// Sets up a secondary renderer (renderer that doesn't [yet] host parts of the -// main test window) for a layout test. -IPC_MESSAGE_ROUTED0(ShellViewMsg_SetupSecondaryRenderer) - // Tells the main window that a secondary renderer in a different process asked // to finish the test. IPC_MESSAGE_ROUTED0(ShellViewMsg_TestFinishedInSecondaryRenderer) @@ -66,9 +41,6 @@ IPC_MESSAGE_ROUTED0(ShellViewMsg_TryLeakDetection) -// Asks a frame to dump its contents into a string and send them back over IPC. -IPC_MESSAGE_ROUTED0(ShellViewMsg_LayoutDumpRequest) - // Notifies BlinkTestRunner that the layout dump has completed // (and that it can proceed with finishing up the test). IPC_MESSAGE_ROUTED1(ShellViewMsg_LayoutDumpCompleted,
diff --git a/content/shell/common/shell_test_configuration.cc b/content/shell/common/shell_test_configuration.cc deleted file mode 100644 index 979adb6..0000000 --- a/content/shell/common/shell_test_configuration.cc +++ /dev/null
@@ -1,15 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/shell/common/shell_test_configuration.h" - -namespace content { - -ShellTestConfiguration::ShellTestConfiguration() - : enable_pixel_dumping(true), - allow_external_pages(false) {} - -ShellTestConfiguration::~ShellTestConfiguration() {} - -} // namespace content
diff --git a/content/shell/common/shell_test_configuration.h b/content/shell/common/shell_test_configuration.h deleted file mode 100644 index 74b5d0b2..0000000 --- a/content/shell/common/shell_test_configuration.h +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_SHELL_COMMON_SHELL_TEST_CONFIGURATION_H_ -#define CONTENT_SHELL_COMMON_SHELL_TEST_CONFIGURATION_H_ - -#include <string> - -#include "base/files/file_path.h" -#include "ui/gfx/geometry/size.h" -#include "url/gurl.h" - -namespace content { - -struct ShellTestConfiguration { - ShellTestConfiguration(); - ~ShellTestConfiguration(); - - // The current working directory. - base::FilePath current_working_directory; - - // The temporary directory of the system. - base::FilePath temp_path; - - // The URL of the current layout test. - GURL test_url; - - // True if pixel tests are enabled. - bool enable_pixel_dumping; - - // True if tests can open external URLs - bool allow_external_pages; - - // The expected MD5 hash of the pixel results. - std::string expected_pixel_hash; - - // The initial size of the test window. - gfx::Size initial_size; -}; - -} // namespace content - -#endif // CONTENT_SHELL_COMMON_SHELL_TEST_CONFIGURATION_H_
diff --git a/content/shell/renderer/layout_test/blink_test_runner.cc b/content/shell/renderer/layout_test/blink_test_runner.cc index aeccd01d..ec2b3185 100644 --- a/content/shell/renderer/layout_test/blink_test_runner.cc +++ b/content/shell/renderer/layout_test/blink_test_runner.cc
@@ -332,7 +332,7 @@ base::FilePath path = base::FilePath::FromUTF8Unsafe(utf8_path); if (!path.IsAbsolute()) { GURL base_url = - net::FilePathToFileURL(test_config_.current_working_directory.Append( + net::FilePathToFileURL(test_config_->current_working_directory.Append( FILE_PATH_LITERAL("foo"))); net::FileURLToFilePath(base_url.Resolve(utf8_path), &path); } @@ -563,7 +563,7 @@ #if defined(OS_WIN) if (base::StartsWith(resource, "/tmp/", base::CompareCase::SENSITIVE)) { // We want a temp file. - GURL base_url = net::FilePathToFileURL(test_config_.temp_path); + GURL base_url = net::FilePathToFileURL(test_config_->temp_path); return base_url.Resolve(resource.substr(sizeof("/tmp/") - 1)).spec(); } #endif @@ -643,7 +643,7 @@ } bool BlinkTestRunner::AllowExternalPages() { - return test_config_.allow_external_pages; + return test_config_->allow_external_pages; } std::string BlinkTestRunner::DumpHistoryForWindow(blink::WebView* web_view) { @@ -896,7 +896,7 @@ void BlinkTestRunner::CaptureDumpContinued() { test_runner::WebTestInterfaces* interfaces = LayoutTestRenderThreadObserver::GetInstance()->test_interfaces(); - if (test_config_.enable_pixel_dumping && + if (test_config_->enable_pixel_dumping && interfaces->TestRunner()->ShouldGeneratePixelResults() && !interfaces->TestRunner()->ShouldDumpAsAudio()) { CHECK(render_view()->GetWebView()->isAcceleratedCompositingActive()); @@ -923,7 +923,7 @@ base::MD5Sum(snapshot.getPixels(), snapshot.getSize(), &digest); std::string actual_pixel_hash = base::MD5DigestToBase16(digest); - if (actual_pixel_hash == test_config_.expected_pixel_hash) { + if (actual_pixel_hash == test_config_->expected_pixel_hash) { SkBitmap empty_image; Send(new ShellViewHostMsg_ImageDump( routing_id(), actual_pixel_hash, empty_image)); @@ -961,27 +961,28 @@ } void BlinkTestRunner::OnReplicateTestConfiguration( - const ShellTestConfiguration& params) { + mojom::ShellTestConfigurationPtr params) { test_runner::WebTestInterfaces* interfaces = LayoutTestRenderThreadObserver::GetInstance()->test_interfaces(); - test_config_ = params; + test_config_ = params.Clone(); is_main_window_ = true; interfaces->SetMainView(render_view()->GetWebView()); interfaces->SetTestIsRunning(true); - interfaces->ConfigureForTestWithURL(params.test_url, - params.enable_pixel_dumping); + interfaces->ConfigureForTestWithURL(params->test_url, + params->enable_pixel_dumping); } void BlinkTestRunner::OnSetTestConfiguration( - const ShellTestConfiguration& params) { - OnReplicateTestConfiguration(params); + mojom::ShellTestConfigurationPtr params) { + mojom::ShellTestConfigurationPtr local_params = params.Clone(); + OnReplicateTestConfiguration(std::move(params)); - ForceResizeRenderView( - render_view(), - WebSize(params.initial_size.width(), params.initial_size.height())); + ForceResizeRenderView(render_view(), + WebSize(local_params->initial_size.width(), + local_params->initial_size.height())); LayoutTestRenderThreadObserver::GetInstance() ->test_interfaces() ->TestRunner()
diff --git a/content/shell/renderer/layout_test/blink_test_runner.h b/content/shell/renderer/layout_test/blink_test_runner.h index 62d7422..21e617e 100644 --- a/content/shell/renderer/layout_test/blink_test_runner.h +++ b/content/shell/renderer/layout_test/blink_test_runner.h
@@ -17,8 +17,8 @@ #include "content/public/common/page_state.h" #include "content/public/renderer/render_view_observer.h" #include "content/public/renderer/render_view_observer_tracker.h" +#include "content/shell/common/layout_test.mojom.h" #include "content/shell/common/layout_test/layout_test_bluetooth_fake_adapter_setter.mojom.h" -#include "content/shell/common/shell_test_configuration.h" #include "v8/include/v8.h" class SkBitmap; @@ -176,8 +176,8 @@ void ReportLeakDetectionResult(const LeakDetectionResult& result); // Message handlers forwarded by LayoutTestRenderFrameObserver. - void OnSetTestConfiguration(const ShellTestConfiguration& params); - void OnReplicateTestConfiguration(const ShellTestConfiguration& params); + void OnSetTestConfiguration(mojom::ShellTestConfigurationPtr params); + void OnReplicateTestConfiguration(mojom::ShellTestConfigurationPtr params); void OnSetupSecondaryRenderer(); private: @@ -210,7 +210,7 @@ test_runner::TestPreferences prefs_; - ShellTestConfiguration test_config_; + mojom::ShellTestConfigurationPtr test_config_; std::vector<int> routing_ids_; std::vector<std::vector<PageState> > session_histories_;
diff --git a/content/shell/renderer/layout_test/layout_test_render_frame_observer.cc b/content/shell/renderer/layout_test/layout_test_render_frame_observer.cc index 4417b57f..0f8aaa0c 100644 --- a/content/shell/renderer/layout_test/layout_test_render_frame_observer.cc +++ b/content/shell/renderer/layout_test/layout_test_render_frame_observer.cc
@@ -8,6 +8,7 @@ #include "components/test_runner/web_test_interfaces.h" #include "components/test_runner/web_test_runner.h" +#include "content/public/common/associated_interface_registry.h" #include "content/public/renderer/render_frame.h" #include "content/shell/common/shell_messages.h" #include "content/shell/renderer/layout_test/blink_test_runner.h" @@ -19,36 +20,28 @@ LayoutTestRenderFrameObserver::LayoutTestRenderFrameObserver( RenderFrame* render_frame) - : RenderFrameObserver(render_frame) { + : RenderFrameObserver(render_frame), binding_(this) { render_frame->GetWebFrame()->setContentSettingsClient( LayoutTestRenderThreadObserver::GetInstance() ->test_interfaces() ->TestRunner() ->GetWebContentSettings()); + render_frame->GetAssociatedInterfaceRegistry()->AddInterface(base::Bind( + &LayoutTestRenderFrameObserver::BindRequest, base::Unretained(this))); } -bool LayoutTestRenderFrameObserver::OnMessageReceived( - const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(LayoutTestRenderFrameObserver, message) - IPC_MESSAGE_HANDLER(ShellViewMsg_LayoutDumpRequest, OnLayoutDumpRequest) - IPC_MESSAGE_HANDLER(ShellViewMsg_ReplicateTestConfiguration, - OnReplicateTestConfiguration) - IPC_MESSAGE_HANDLER(ShellViewMsg_SetTestConfiguration, - OnSetTestConfiguration) - IPC_MESSAGE_HANDLER(ShellViewMsg_SetupSecondaryRenderer, - OnSetupSecondaryRenderer) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() +LayoutTestRenderFrameObserver::~LayoutTestRenderFrameObserver() = default; - return handled; +void LayoutTestRenderFrameObserver::BindRequest( + mojom::LayoutTestControlAssociatedRequest request) { + binding_.Bind(std::move(request)); } void LayoutTestRenderFrameObserver::OnDestruct() { delete this; } -void LayoutTestRenderFrameObserver::OnLayoutDumpRequest() { +void LayoutTestRenderFrameObserver::LayoutDumpRequest() { std::string dump = LayoutTestRenderThreadObserver::GetInstance() ->test_interfaces() @@ -57,19 +50,19 @@ Send(new ShellViewHostMsg_LayoutDumpResponse(routing_id(), dump)); } -void LayoutTestRenderFrameObserver::OnReplicateTestConfiguration( - const ShellTestConfiguration& test_config) { +void LayoutTestRenderFrameObserver::ReplicateTestConfiguration( + mojom::ShellTestConfigurationPtr config) { BlinkTestRunner::Get(render_frame()->GetRenderView()) - ->OnReplicateTestConfiguration(test_config); + ->OnReplicateTestConfiguration(std::move(config)); } -void LayoutTestRenderFrameObserver::OnSetTestConfiguration( - const ShellTestConfiguration& test_config) { +void LayoutTestRenderFrameObserver::SetTestConfiguration( + mojom::ShellTestConfigurationPtr config) { BlinkTestRunner::Get(render_frame()->GetRenderView()) - ->OnSetTestConfiguration(test_config); + ->OnSetTestConfiguration(std::move(config)); } -void LayoutTestRenderFrameObserver::OnSetupSecondaryRenderer() { +void LayoutTestRenderFrameObserver::SetupSecondaryRenderer() { BlinkTestRunner::Get(render_frame()->GetRenderView()) ->OnSetupSecondaryRenderer(); }
diff --git a/content/shell/renderer/layout_test/layout_test_render_frame_observer.h b/content/shell/renderer/layout_test/layout_test_render_frame_observer.h index 230ec1ce..bd620c08 100644 --- a/content/shell/renderer/layout_test/layout_test_render_frame_observer.h +++ b/content/shell/renderer/layout_test/layout_test_render_frame_observer.h
@@ -7,33 +7,29 @@ #include "base/macros.h" #include "content/public/renderer/render_frame_observer.h" - -namespace IPC { -class Message; -} // namespace IPC +#include "content/shell/common/layout_test.mojom.h" +#include "mojo/public/cpp/bindings/associated_binding.h" namespace content { -struct ShellTestConfiguration; -class RenderFrame; -struct ShellTestConfiguration; -class LayoutTestRenderFrameObserver : public RenderFrameObserver { +class LayoutTestRenderFrameObserver : public RenderFrameObserver, + public mojom::LayoutTestControl { public: explicit LayoutTestRenderFrameObserver(RenderFrame* render_frame); - ~LayoutTestRenderFrameObserver() override {} - - // RenderFrameObserver implementation. - bool OnMessageReceived(const IPC::Message& message) override; + ~LayoutTestRenderFrameObserver() override; private: // RenderFrameObserver implementation. void OnDestruct() override; - void OnLayoutDumpRequest(); - void OnSetTestConfiguration(const ShellTestConfiguration& test_config); - void OnReplicateTestConfiguration(const ShellTestConfiguration& test_config); - void OnSetupSecondaryRenderer(); + void LayoutDumpRequest() override; + void SetTestConfiguration(mojom::ShellTestConfigurationPtr config) override; + void ReplicateTestConfiguration( + mojom::ShellTestConfigurationPtr config) override; + void SetupSecondaryRenderer() override; + void BindRequest(mojom::LayoutTestControlAssociatedRequest request); + mojo::AssociatedBinding<mojom::LayoutTestControl> binding_; DISALLOW_COPY_AND_ASSIGN(LayoutTestRenderFrameObserver); };
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 5d97c20..6268be8 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -620,6 +620,7 @@ "../browser/message_port_provider_browsertest.cc", "../browser/mojo_sandbox_browsertest.cc", "../browser/net_info_browsertest.cc", + "../browser/payments/payment_app_browsertest.cc", "../browser/presentation/presentation_browsertest.cc", "../browser/renderer_host/input/composited_scrolling_browsertest.cc", "../browser/renderer_host/input/main_thread_event_queue_browsertest.cc", @@ -690,6 +691,7 @@ "//components/discardable_memory/client", "//components/discardable_memory/common", "//components/discardable_memory/service", + "//components/payments:payment_app", "//content:resources", "//content/app:both_for_content_tests", "//content/browser:for_content_tests", @@ -1227,6 +1229,7 @@ "../browser/renderer_host/render_widget_host_view_mac_unittest.mm", "../browser/renderer_host/text_input_client_mac_unittest.mm", "../browser/resolve_proxy_msg_helper_unittest.cc", + "../browser/screen_orientation/screen_orientation_provider_unittest.cc", "../browser/service_manager/merge_dictionary_unittest.cc", "../browser/service_worker/embedded_worker_instance_unittest.cc", "../browser/service_worker/foreign_fetch_request_handler_unittest.cc", @@ -1548,17 +1551,16 @@ "../browser/webrtc/webrtc_eventlog_host_unittest.cc", "../browser/webrtc/webrtc_internals_unittest.cc", "../renderer/media/audio_repetition_detector_unittest.cc", - "../renderer/media/audio_track_recorder_unittest.cc", - "../renderer/media/canvas_capture_handler_unittest.cc", + "../renderer/media/capturefromelement/canvas_capture_handler_unittest.cc", + "../renderer/media/capturefromelement/html_audio_element_capturer_source_unittest.cc", + "../renderer/media/capturefromelement/html_video_element_capturer_source_unittest.cc", "../renderer/media/gpu/rtc_video_decoder_unittest.cc", "../renderer/media/gpu/rtc_video_encoder_unittest.cc", - "../renderer/media/html_audio_element_capturer_source_unittest.cc", - "../renderer/media/html_video_element_capturer_source_unittest.cc", "../renderer/media/media_devices_event_dispatcher_unittest.cc", - "../renderer/media/media_recorder_handler_unittest.cc", "../renderer/media/media_stream_audio_processor_unittest.cc", "../renderer/media/media_stream_audio_unittest.cc", "../renderer/media/media_stream_constraints_util_unittest.cc", + "../renderer/media/media_stream_constraints_util_video_source_unittest.cc", "../renderer/media/media_stream_dispatcher_unittest.cc", "../renderer/media/media_stream_video_capturer_source_unittest.cc", "../renderer/media/media_stream_video_renderer_sink_unittest.cc", @@ -1572,11 +1574,13 @@ "../renderer/media/mock_media_stream_video_source.cc", "../renderer/media/mock_media_stream_video_source.h", "../renderer/media/peer_connection_tracker_unittest.cc", + "../renderer/media/recorder/audio_track_recorder_unittest.cc", + "../renderer/media/recorder/media_recorder_handler_unittest.cc", + "../renderer/media/recorder/video_track_recorder_unittest.cc", "../renderer/media/rtc_data_channel_handler_unittest.cc", "../renderer/media/rtc_peer_connection_handler_unittest.cc", "../renderer/media/speech_recognition_audio_sink_unittest.cc", "../renderer/media/user_media_client_impl_unittest.cc", - "../renderer/media/video_track_recorder_unittest.cc", "../renderer/media/webrtc/media_stream_remote_video_source_unittest.cc", "../renderer/media/webrtc/media_stream_track_metrics_unittest.cc", "../renderer/media/webrtc/media_stream_video_webrtc_sink_unittest.cc", @@ -1614,9 +1618,9 @@ if (is_chromecast) { sources -= [ - "../renderer/media/audio_track_recorder_unittest.cc", - "../renderer/media/media_recorder_handler_unittest.cc", - "../renderer/media/video_track_recorder_unittest.cc", + "../renderer/media/recorder/audio_track_recorder_unittest.cc", + "../renderer/media/recorder/media_recorder_handler_unittest.cc", + "../renderer/media/recorder/video_track_recorder_unittest.cc", ] } }
diff --git a/content/test/blink_test_environment.cc b/content/test/blink_test_environment.cc index 7790025..51066254 100644 --- a/content/test/blink_test_environment.cc +++ b/content/test/blink_test_environment.cc
@@ -17,7 +17,7 @@ #include "content/public/common/user_agent.h" #include "content/public/test/test_content_client_initializer.h" #include "content/test/test_blink_web_unit_test_support.h" -#include "third_party/WebKit/public/web/WebCache.h" +#include "third_party/WebKit/public/platform/WebCache.h" #include "third_party/WebKit/public/web/WebKit.h" #include "third_party/WebKit/public/web/WebRuntimeFeatures.h" #include "url/url_util.h"
diff --git a/content/test/data/payments/payment_app.js b/content/test/data/payments/payment_app.js new file mode 100644 index 0000000..a3b40e70 --- /dev/null +++ b/content/test/data/payments/payment_app.js
@@ -0,0 +1,42 @@ +// 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. + +function sendResultToTest(data) { + clients.matchAll({includeUncontrolled: true}).then(clients => { + clients.forEach(client => { + if (client.url.indexOf('payment_app_invocation.html') != -1) { + client.postMessage(data); + } + }); + }); +} + +function getMessageFromPaymentAppWindow() { + return new Promise((resolve, reject) => { + var listener = self.addEventListener('message', e => { + resolve(e.data); + self.removeEventListener(listener); + }); + }); +} + +self.addEventListener('paymentrequest', e => { + var payment_app_window; + + // SW ------------------ openWindow() -----------------> payment_app_window + // SW <---- postMessage('payment_app_window_ready') ---- payment_app_window + // SW ------- postMessage('payment_app_request') ------> payment_app_window + // SW <------ postMessage('payment_app_response') ------ payment_app_window + e.waitUntil(clients.openWindow('payment_app_window.html') + .then(window_client => { + payment_app_window = window_client; + return getMessageFromPaymentAppWindow(); + }) + .then(message => { + sendResultToTest(message); + payment_app_window.postMessage('payment_app_request'); + return getMessageFromPaymentAppWindow(); + }) + .then(message => { sendResultToTest(message); })); +});
diff --git a/content/test/data/payments/payment_app_invocation.html b/content/test/data/payments/payment_app_invocation.html new file mode 100644 index 0000000..672992b4 --- /dev/null +++ b/content/test/data/payments/payment_app_invocation.html
@@ -0,0 +1,36 @@ +<!doctype html> +<title>Payment App: Test for invoking payment app</title> +<script src="./result_queue.js"></script> +<script> + +function registerPaymentApp() { + navigator.serviceWorker.register('payment_app.js', { scope: './' }) + .then(() => { + return navigator.serviceWorker.ready; + }) + .then(registration => { + return registration.paymentAppManager.setManifest({ + name: 'Payment App', + icon: 'payment-app-icon', + options: [{ + name: 'Visa ****', + icon: 'payment-app-icon', + id: 'payment-app-id', + enabledMethods: ['visa'] + }] + }); + }) + .then(result => { + sendResultToTest('registered'); + }) + .catch(result => { + sendResultToTest('error'); + }); +} + +var resultQueue = new ResultQueue(); +navigator.serviceWorker.addEventListener('message', e => { + resultQueue.push(e.data); +}); + +</script>
diff --git a/content/test/data/payments/payment_app_window.html b/content/test/data/payments/payment_app_window.html new file mode 100644 index 0000000..0ed713f --- /dev/null +++ b/content/test/data/payments/payment_app_window.html
@@ -0,0 +1,10 @@ +<!doctype html> +<script> + +navigator.serviceWorker.addEventListener('message', e => { + e.source.postMessage('payment_app_response'); + window.close(); +}); +navigator.serviceWorker.controller.postMessage('payment_app_window_ready'); + +</script>
diff --git a/content/test/data/payments/result_queue.js b/content/test/data/payments/result_queue.js new file mode 100644 index 0000000..cb90a97 --- /dev/null +++ b/content/test/data/payments/result_queue.js
@@ -0,0 +1,52 @@ +// 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. + +// Queue storing asynchronous results received from the Service Worker. Results +// are sent to the test when requested. +function ResultQueue() { + // Invariant: this.queue.length == 0 || this.pendingGets == 0 + this.queue = []; + this.pendingGets = 0; +} + +// Adds a data item to the queue. Will be sent to the test if there are +// pendingGets. +ResultQueue.prototype.push = function(data) { + if (this.pendingGets > 0) { + this.pendingGets--; + sendResultToTest(data); + } else { + this.queue.unshift(data); + } +}; + +// Called by native. Sends the next data item to the test if it is available. +// Otherwise increments pendingGets so it will be delivered when received. +ResultQueue.prototype.pop = function() { + if (this.queue.length) { + sendResultToTest(this.queue.pop()); + } else { + this.pendingGets++; + } +}; + +// Called by native. Immediately sends the next data item to the test if it is +// available, otherwise sends null. +ResultQueue.prototype.popImmediately = function() { + sendResultToTest(this.queue.length ? this.queue.pop() : null); +}; + +// Sends data back to the test. This must be in response to an earlier +// request, but it's ok to respond asynchronously. The request blocks until +// the response is sent. +function sendResultToTest(result) { + console.log('sendResultToTest: ' + result); + if (window.domAutomationController) { + domAutomationController.send('' + result); + } +} + +function sendErrorToTest(error) { + sendResultToTest(error.name + ' - ' + error.message); +}
diff --git a/content/test/gpu/OWNERS b/content/test/gpu/OWNERS index 77c472e5..a2f60e1 100644 --- a/content/test/gpu/OWNERS +++ b/content/test/gpu/OWNERS
@@ -8,3 +8,5 @@ # Emeritus: # dtu@chromium.org + +# COMPONENT: Test
diff --git a/content/test/gpu/generate_buildbot_json.py b/content/test/gpu/generate_buildbot_json.py index 79c00ec4..0ad1f3e 100755 --- a/content/test/gpu/generate_buildbot_json.py +++ b/content/test/gpu/generate_buildbot_json.py
@@ -138,54 +138,6 @@ 'swarming': True, 'os_type': 'mac', }, - # BEGIN obsolete Mac bots -- remove after waterfall restarted successfully. - 'Mac 10.10 Release (Intel)': { - 'swarming_dimensions': [ - { - 'gpu': '8086:0a2e', - 'os': 'Mac-10.12' - }, - ], - 'build_config': 'Release', - 'swarming': True, - 'os_type': 'mac', - }, - 'Mac 10.10 Debug (Intel)': { - 'swarming_dimensions': [ - { - 'gpu': '8086:0a2e', - 'os': 'Mac-10.12' - }, - ], - 'build_config': 'Debug', - 'swarming': True, - 'os_type': 'mac', - }, - 'Mac 10.10 Retina Release (AMD)': { - 'swarming_dimensions': [ - { - 'gpu': '1002:6821', - 'hidpi': '1', - 'os': 'Mac' - }, - ], - 'build_config': 'Release', - 'swarming': True, - 'os_type': 'mac', - }, - 'Mac 10.10 Retina Debug (AMD)': { - 'swarming_dimensions': [ - { - 'gpu': '1002:6821', - 'hidpi': '1', - 'os': 'Mac' - }, - ], - 'build_config': 'Debug', - 'swarming': True, - 'os_type': 'mac', - }, - # END obsolete Mac bots -- remove after waterfall restarted successfully. 'Linux Release (NVIDIA)': { 'swarming_dimensions': [ { @@ -399,117 +351,6 @@ 'swarming': True, 'os_type': 'win', }, - # BEGIN obsolete Mac bots -- remove after waterfall restarted successfully. - 'Mac 10.10 Release (Intel)': { - 'swarming_dimensions': [ - { - 'gpu': '8086:0a2e', - 'os': 'Mac-10.12' - }, - ], - 'build_config': 'Release', - 'swarming': True, - 'os_type': 'mac', - }, - 'Mac 10.10 Debug (Intel)': { - 'swarming_dimensions': [ - { - 'gpu': '8086:0a2e', - 'os': 'Mac-10.12' - }, - ], - 'build_config': 'Debug', - 'swarming': True, - 'os_type': 'mac', - }, - 'Mac 10.10 Release (AMD)': { - 'swarming_dimensions': [ - { - 'gpu': '1002:679e', - 'os': 'Mac-10.10' - }, - ], - 'build_config': 'Release', - # This bot is a one-off and doesn't have similar slaves in the - # swarming pool. - 'swarming': False, - 'os_type': 'mac', - }, - 'Mac 10.10 Debug (AMD)': { - 'swarming_dimensions': [ - { - 'gpu': '1002:679e', - 'os': 'Mac-10.10' - }, - ], - 'build_config': 'Debug', - # This bot is a one-off and doesn't have similar slaves in the - # swarming pool. - 'swarming': False, - 'os_type': 'mac', - }, - 'Mac Retina Release': { - 'swarming_dimensions': [ - { - 'gpu': '10de:0fe9', - 'hidpi': '1', - 'os': 'Mac' - }, - ], - 'build_config': 'Release', - 'swarming': True, - 'os_type': 'mac', - }, - 'Mac Retina Debug': { - 'swarming_dimensions': [ - { - 'gpu': '10de:0fe9', - 'hidpi': '1', - 'os': 'Mac' - }, - ], - 'build_config': 'Debug', - 'swarming': True, - 'os_type': 'mac', - }, - 'Mac 10.10 Retina Release (AMD)': { - 'swarming_dimensions': [ - { - 'gpu': '1002:6821', - 'hidpi': '1', - 'os': 'Mac' - }, - ], - 'build_config': 'Release', - 'swarming': True, - 'os_type': 'mac', - }, - 'Mac 10.10 Retina Debug (AMD)': { - 'swarming_dimensions': [ - { - 'gpu': '1002:6821', - 'hidpi': '1', - 'os': 'Mac' - }, - ], - 'build_config': 'Debug', - 'swarming': True, - 'os_type': 'mac', - }, - 'Mac 10.11 Retina Release (AMD)': { - 'swarming_dimensions': [ - { - 'gpu': '1002:6821', - 'hidpi': '1', - 'os': 'Mac' - }, - ], - 'build_config': 'Release', - # This bot is a one-off for testing purposes. - 'swarming': False, - 'os_type': 'mac', - }, - # END obsolete Mac bots -- remove after waterfall restarted successfully. 'Mac Release (Intel)': { 'swarming_dimensions': [ {
diff --git a/content/test/gpu/gpu_tests/fake_win_amd_gpu_info.py b/content/test/gpu/gpu_tests/fake_win_amd_gpu_info.py index 2f63b610..db01709 100644 --- a/content/test/gpu/gpu_tests/fake_win_amd_gpu_info.py +++ b/content/test/gpu/gpu_tests/fake_win_amd_gpu_info.py
@@ -36,7 +36,6 @@ }, 'aux_attributes': { - 'adapter_luid': 0.0, 'amd_switchable': False, 'basic_info_state': 1, 'context_info_state': 1, @@ -85,7 +84,6 @@ 'in_process_gpu': False, 'initialization_time': 2.503214, 'jpeg_decode_accelerator_supported': False, - 'lenovo_dcute': False, 'max_msaa_samples': '4', 'max_resolution_height': 1088, 'max_resolution_width': 1920,
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py index 34e0634..91ddb49 100644 --- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -52,10 +52,12 @@ 'integer-cubemap-specification-order-bug.html', bug=483282) # owner:cwallez, test might be buggy + # Win and Mac + self.Flaky('deqp/functional/gles3/sync.html', ['win', 'mac'], bug=676848) + # Windows only. self.Fail('conformance2/rendering/blitframebuffer-outside-readbuffer.html', ['win'], bug=644740) - self.Flaky('deqp/functional/gles3/sync.html', ['win'], bug=676848) # Win / NVidia self.Flaky('deqp/functional/gles3/fbomultisample*', @@ -529,21 +531,6 @@ ['mac', 'amd', 'intel'], bug=679691) # Mac Intel - - # ASAN only - self.Fail( - 'conformance/more/functions/copyTexImage2D.html', - ['mac', 'intel', 'asan'], bug=680845) - self.Fail( - 'conformance/more/functions/copyTexSubImage2D.html', - ['mac', 'intel', 'asan'], bug=680845) - self.Fail( - 'deqp/functional/gles3/negativetextureapi.html', - ['mac', 'intel', 'asan'], bug=680845) - self.Fail( - 'deqp/functional/gles3/texturespecification/basic_copyteximage2d.html', - ['mac', 'intel', 'asan'], bug=680845) - self.Fail( 'conformance2/textures/canvas/tex-2d-rgb9_e5-rgb-float.html', ['sierra', 'intel'], bug=663188) @@ -668,6 +655,17 @@ self.Fail('deqp/functional/gles3/uniformbuffers/random.html', ['mac', 'intel'], bug=618464) + # Mac ASAN only + self.Fail('conformance/more/functions/copyTexImage2D.html', + ['mac', 'asan'], bug=681641) + self.Fail('conformance/more/functions/copyTexSubImage2D.html', + ['mac', 'asan'], bug=681641) + self.Fail('deqp/functional/gles3/negativetextureapi.html', + ['mac', 'asan'], bug=681641) + self.Fail( + 'deqp/functional/gles3/texturespecification/basic_copyteximage2d.html', + ['mac', 'asan'], bug=681641) + # Linux only. self.Flaky('conformance/textures/video/' + 'tex-2d-rgba-rgba-unsigned_byte.html',
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py index 3ac86fa..44918e6 100644 --- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -87,8 +87,6 @@ self.Fail('WebglExtension_WEBGL_draw_buffers', ['android']) - # Nexus 6 (Adreno 420) and 6P (Adreno 430) - # ======================== # Conformance expectations # ======================== @@ -396,8 +394,6 @@ self.Flaky('conformance/textures/video/' + 'tex-2d-rgb-rgb-unsigned_short_5_6_5.html', ['linux'], bug=627525) - self.Fail('conformance/extensions/webgl-compressed-texture-etc.html', - bug=679678) self.Fail('conformance/extensions/webgl-compressed-texture-astc.html', ['linux', 'intel'], bug=680675) @@ -532,17 +528,6 @@ ['android', ('qualcomm', 'Adreno (TM) 330')], bug=678850) # Nexus 5X - self.Fail('conformance/extensions/oes-texture-float-with-image-data.html', - ['android', ('qualcomm', 'Adreno (TM) 418')], bug=609883) - self.Fail('conformance/extensions/oes-texture-float-with-image.html', - ['android', ('qualcomm', 'Adreno (TM) 418')], bug=609883) - self.Fail('conformance/extensions/oes-texture-half-float-with-canvas.html', - ['android', ('qualcomm', 'Adreno (TM) 418')], bug=609883) - self.Fail('conformance/extensions/' + - 'oes-texture-half-float-with-image-data.html', - ['android', ('qualcomm', 'Adreno (TM) 418')], bug=609883) - self.Fail('conformance/extensions/oes-texture-half-float-with-image.html', - ['android', ('qualcomm', 'Adreno (TM) 418')], bug=609883) # This one is causing intermittent timeouts on the device, and it # looks like when that happens, the next test also always times # out. Skip it for now until it's fixed and running reliably. @@ -555,32 +540,6 @@ # This test is skipped because it is crashing the GPU process. self.Skip('conformance/glsl/misc/shader-with-non-reserved-words.html', ['android', ('qualcomm', 'Adreno (TM) 418')], bug=609883) - self.Fail('conformance/textures/misc/' + - 'tex-image-and-sub-image-2d-with-array-buffer-view.html', - ['android', ('qualcomm', 'Adreno (TM) 418')], bug=610951) - self.Fail('conformance/textures/canvas/*', - ['android', ('qualcomm', 'Adreno (TM) 418')], bug=610951) - self.Fail('conformance/textures/image/*', - ['android', ('qualcomm', 'Adreno (TM) 418')], bug=610951) - self.Fail('conformance/textures/image_bitmap_from_canvas/*', - ['android', ('qualcomm', 'Adreno (TM) 418')], bug=610951) - self.Fail('conformance/textures/image_bitmap_from_blob/*', - ['android', ('qualcomm', 'Adreno (TM) 418')], bug=610951) - self.Fail('conformance/textures/image_bitmap_from_image/*', - ['android', ('qualcomm', 'Adreno (TM) 418')], bug=610951) - self.Fail('conformance/textures/image_bitmap_from_image_bitmap/*', - ['android', ('qualcomm', 'Adreno (TM) 418')], bug=610951) - self.Fail('conformance/textures/image_bitmap_from_image_data/*', - ['android', ('qualcomm', 'Adreno (TM) 418')], bug=610951) - self.Fail('conformance/textures/image_data/*', - ['android', ('qualcomm', 'Adreno (TM) 418')], bug=610951) - self.Fail('conformance/textures/svg_image/*', - ['android', ('qualcomm', 'Adreno (TM) 418')], bug=610951) - self.Fail('conformance/textures/video/*', - ['android', 'android-content-shell', 'android-chromium', - ('qualcomm', 'Adreno (TM) 418')], bug=610951) - self.Fail('conformance/textures/webgl_canvas/*', - ['android', ('qualcomm', 'Adreno (TM) 418')], bug=610951) self.Fail('conformance/uniforms/uniform-samplers-test.html', ['android', ('qualcomm', 'Adreno (TM) 418')], bug=610951) self.Fail('WebglExtension_EXT_sRGB',
diff --git a/content/test/run_all_unittests.cc b/content/test/run_all_unittests.cc index ad71509..153442c 100644 --- a/content/test/run_all_unittests.cc +++ b/content/test/run_all_unittests.cc
@@ -4,6 +4,7 @@ #include "base/bind.h" #include "base/test/launcher/unit_test_launcher.h" +#include "base/values.h" #include "content/public/test/unittest_test_suite.h" #include "content/test/content_test_suite.h" #include "content/test/content_unittests_catalog_source.h"
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc index 928e237..ff25114 100644 --- a/content/test/test_render_frame_host.cc +++ b/content/test/test_render_frame_host.cc
@@ -24,6 +24,7 @@ #include "content/test/test_render_view_host.h" #include "mojo/public/cpp/bindings/interface_request.h" #include "net/base/load_flags.h" +#include "net/http/http_response_headers.h" #include "third_party/WebKit/public/platform/WebMixedContentContextType.h" #include "third_party/WebKit/public/platform/WebPageVisibilityState.h" #include "third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom.h" @@ -399,6 +400,13 @@ void TestRenderFrameHost::SendNavigateWithParams( FrameHostMsg_DidCommitProvisionalLoad_Params* params) { + if (navigation_handle()) { + scoped_refptr<net::HttpResponseHeaders> response_headers = + new net::HttpResponseHeaders(std::string()); + response_headers->AddHeader( + std::string("Content-Type: ") + contents_mime_type_); + navigation_handle()->set_response_headers_for_testing(response_headers); + } FrameHostMsg_DidCommitProvisionalLoad msg(GetRoutingID(), *params); OnDidCommitProvisionalLoad(msg); last_commit_was_error_page_ = params->url_is_unreachable;
diff --git a/device/gamepad/OWNERS b/device/gamepad/OWNERS index 16c21dcb..a601d2e 100644 --- a/device/gamepad/OWNERS +++ b/device/gamepad/OWNERS
@@ -1,2 +1,4 @@ scottmg@chromium.org bajones@chromium.org + +# COMPONENT: IO>Gamepad
diff --git a/device/power_monitor/OWNERS b/device/power_monitor/OWNERS index 887a99be..92c60edb 100644 --- a/device/power_monitor/OWNERS +++ b/device/power_monitor/OWNERS
@@ -1,2 +1,4 @@ bajones@chromium.org blundell@chromium.org + +# COMPONENT: Manifest
diff --git a/device/usb/mojo/type_converters.h b/device/usb/mojo/type_converters.h index 92df665..cd4a405 100644 --- a/device/usb/mojo/type_converters.h +++ b/device/usb/mojo/type_converters.h
@@ -25,12 +25,6 @@ namespace mojo { template <> -struct TypeConverter<device::UsbDeviceFilter, device::usb::DeviceFilterPtr> { - static device::UsbDeviceFilter Convert( - const device::usb::DeviceFilterPtr& mojo_filter); -}; - -template <> struct TypeConverter<device::usb::TransferDirection, device::UsbEndpointDirection> { static device::usb::TransferDirection Convert(
diff --git a/device/vr/OWNERS b/device/vr/OWNERS index a77a5d4..7849628 100644 --- a/device/vr/OWNERS +++ b/device/vr/OWNERS
@@ -5,3 +5,5 @@ per-file *.mojom=set noparent per-file *.mojom=file://ipc/SECURITY_OWNERS + +# COMPONENT: UI>Browser>VR
diff --git a/docs/linux_zygote.md b/docs/linux_zygote.md index 5504115..da7c841 100644 --- a/docs/linux_zygote.md +++ b/docs/linux_zygote.md
@@ -3,10 +3,20 @@ after some expensive setup has been performed can save time and share extra memory pages. -On Linux, for Chromium, this is not the point, and measurements suggest that the -time and memory savings are minimal or negative. +More specifically, on Linux, it allows to: + * Amortize the runtime and memory cost of the dynamic loader's relocations, + which is respectively ~6 MB and 60 ms/GHz per process. + See [Appendix A](#appendix-a-runtime-impact-of-relocations) and + [Appendix B](#appendix-b-memory-impact-of-relocations). + * Amortize the runtime and memory cost for initializing common + libraries, such as ICU, NSS, the V8 snapshot and anything else in + `ContentMainRunnerImpl::Initialize()`. With the above, this saves + up to ~8 MB per process. See [Appendix C](#appendix-c-overall-memory-impact). -We use it because it's the only reasonable way to keep a reference to a binary +Security-wise, the Zygote is responsible for setting up and bookkeeping the +[namespace sandbox](linux_sandboxing.md). + +Furthermore it is the only reasonable way to keep a reference to a binary and a set of shared libraries that can be exec'ed. In the model used on Windows and Mac, renderers are exec'ed as needed from the chrome binary. However, if the chrome binary, or any of its shared libraries are updated while Chrome is @@ -34,3 +44,37 @@ You can use the `--zygote-cmd-prefix` flag to debug the zygote process. If you use `--renderer-cmd-prefix` then the zygote will be bypassed and renderers will be exec'ed afresh every time. + +## Appendix A: Runtime impact of relocations +Measured on a Z620: + + $ LD_DEBUG=statistics /opt/google/chrome-beta/chrome --help + runtime linker statistics: + total startup time in dynamic loader: 73899158 clock cycles + time needed for relocation: 56836478 clock cycles (76.9%) + number of relocations: 4271 + number of relocations from cache: 11347 + number of relative relocations: 502740 + time needed to load objects: 15789844 clock cycles (21.3%) + +56836478 clock cycles -> ~56 ms/GHz + +## Appendix B: Memory impact of relocations + + $ readelf -WS /opt/google/chrome-beta/chrome + [Nr] Name Type Address Off Size ES Flg Lk Inf Al + ... + [25] .data.rel.ro PROGBITS 0000000006a8b590 6a8a590 5b5500 00 WA 0 0 16 + ... + Note: 0x5b5500 -> 5.98 MB + +Actual impact in terms of memory pages that get shared due to CoW: + + $ cat /proc/.../smaps + 7fbdd1c81000-7fbdd2233000 r--p 06a5d000 fc:00 665771 /opt/google/chrome-unstable/chrome + ... + Shared_Dirty: 5796 kB + +## Appendix C: Overall memory impact + $ cat /proc/$PID_OF_ZYGOTE/smaps | grep Shared_Dirty | awk '{TOTAL += $2} END {print TOTAL}' + 8092 # KB for dirty pages shared with other processes (mostly forked child processes).
diff --git a/extensions/BUILD.gn b/extensions/BUILD.gn index 8ee9a89..0b11984 100644 --- a/extensions/BUILD.gn +++ b/extensions/BUILD.gn
@@ -56,6 +56,7 @@ "//extensions/common:mojo__generator", "//extensions/common/api:mojom__generator", "//mojo/common:common_custom_types__generator", + "//url/mojo:url_mojom_origin__generator", ] }
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc index 78e70d7..90aad5c 100644 --- a/extensions/renderer/dispatcher.cc +++ b/extensions/renderer/dispatcher.cc
@@ -745,6 +745,7 @@ {"chrome/browser/media/router/mojo/media_router.mojom", IDR_MEDIA_ROUTER_MOJOM_JS}, {"mojo/common/time.mojom", IDR_MOJO_TIME_MOJOM_JS}, + {"url/mojo/origin.mojom", IDR_ORIGIN_MOJOM_JS}, {"media_router_bindings", IDR_MEDIA_ROUTER_BINDINGS_JS}, #endif // defined(ENABLE_MEDIA_ROUTER) };
diff --git a/extensions/renderer/extension_frame_helper.cc b/extensions/renderer/extension_frame_helper.cc index c737aa55..3985bd6 100644 --- a/extensions/renderer/extension_frame_helper.cc +++ b/extensions/renderer/extension_frame_helper.cc
@@ -187,7 +187,8 @@ stopped_matching_selectors); } -void ExtensionFrameHelper::DidStartProvisionalLoad() { +void ExtensionFrameHelper::DidStartProvisionalLoad( + blink::WebDataSource* data_source) { if (!delayed_main_world_script_initialization_) return;
diff --git a/extensions/renderer/extension_frame_helper.h b/extensions/renderer/extension_frame_helper.h index f45129e..ee91a76d 100644 --- a/extensions/renderer/extension_frame_helper.h +++ b/extensions/renderer/extension_frame_helper.h
@@ -90,7 +90,7 @@ const blink::WebVector<blink::WebString>& newly_matching_selectors, const blink::WebVector<blink::WebString>& stopped_matching_selectors) override; - void DidStartProvisionalLoad() override; + void DidStartProvisionalLoad(blink::WebDataSource* data_source) override; void DidCreateScriptContext(v8::Local<v8::Context>, int world_id) override; void WillReleaseScriptContext(v8::Local<v8::Context>, int world_id) override;
diff --git a/extensions/renderer/resources/extensions_renderer_resources.grd b/extensions/renderer/resources/extensions_renderer_resources.grd index f6807f9..984f61e 100644 --- a/extensions/renderer/resources/extensions_renderer_resources.grd +++ b/extensions/renderer/resources/extensions_renderer_resources.grd
@@ -89,6 +89,7 @@ <include name="IDR_MEDIA_ROUTER_MOJOM_JS" file="${mojom_root}\chrome\browser\media\router\mojo\media_router.mojom.js" use_base_dir="false" type="BINDATA" /> <include name="IDR_MEDIA_ROUTER_BINDINGS_JS" file="media_router_bindings.js" type="BINDATA" /> <include name="IDR_MOJO_TIME_MOJOM_JS" file="${mojom_root}\mojo\common\time.mojom.js" use_base_dir="false" type="BINDATA" /> + <include name="IDR_ORIGIN_MOJOM_JS" file="${mojom_root}\url\mojo\origin.mojom.js" use_base_dir="false" type="BINDATA" /> </if> </includes> <structures>
diff --git a/extensions/renderer/resources/media_router_bindings.js b/extensions/renderer/resources/media_router_bindings.js index 0373e036..7aeb83d8 100644 --- a/extensions/renderer/resources/media_router_bindings.js +++ b/extensions/renderer/resources/media_router_bindings.js
@@ -10,11 +10,13 @@ 'extensions/common/mojo/keep_alive.mojom', 'mojo/common/time.mojom', 'mojo/public/js/bindings', + 'url/mojo/origin.mojom', ], function(frameInterfaces, mediaRouterMojom, keepAliveMojom, timeMojom, - bindings) { + bindings, + originMojom) { 'use strict'; /** @@ -143,6 +145,43 @@ } } + // TODO(crbug.com/688177): remove this conversion. + /** + * Converts Mojo origin to string. + * @param {!originMojom.Origin} Mojo origin + * @return {string} + */ + function mojoOriginToString_(origin) { + return origin.unique ? '' : + `${origin.scheme}:\/\/${origin.host}` + + `${origin.port ? `:${origin.port}` : ''}/` + } + + // TODO(crbug.com/688177): remove this conversion. + /** + * Converts string to Mojo origin. + * @param {string} origin + * @return {!originMojom.Origin} + */ + function stringToMojoOrigin_(origin) { + var url = new URL(origin); + var mojoOrigin = {}; + mojoOrigin.scheme = url.protocol.replace(':', ''); + mojoOrigin.host = url.hostname; + var port = url.port ? Number.parseInt(url.port) : 0; + switch (mojoOrigin.scheme) { + case 'http': + mojoOrigin.port = port || 80; + break; + case 'https': + mojoOrigin.port = port || 443; + break; + default: + throw new Error('Scheme must be http or https'); + } + return new originMojom.Origin(mojoOrigin); + } + /** * Parses the given route request Error object and converts it to the * corresponding result code. @@ -254,7 +293,7 @@ MediaRouter.prototype.onSinksReceived = function(sourceUrn, sinks, origins) { this.service_.onSinksReceived(sourceUrn, sinks.map(sinkToMojo_), - origins); + origins.map(stringToMojoOrigin_)); }; /** @@ -572,7 +611,7 @@ * @param {!string} sinkId Media sink ID. * @param {!string} presentationId Presentation ID from the site * requesting presentation. TODO(mfoltz): Remove. - * @param {!string} origin Origin of site requesting presentation. + * @param {!originMojom.Origin} origin Origin of site requesting presentation. * @param {!number} tabId ID of tab requesting presentation. * @param {!TimeDelta} timeout If positive, the timeout duration for the * request. Otherwise, the default duration will be used. @@ -587,7 +626,7 @@ timeout, incognito) { this.handlers_.onBeforeInvokeHandler(); return this.handlers_.createRoute( - sourceUrn, sinkId, presentationId, origin, tabId, + sourceUrn, sinkId, presentationId, mojoOriginToString_(origin), tabId, Math.floor(timeout.microseconds / 1000), incognito) .then(function(route) { return toSuccessRouteResponse_(route); @@ -603,7 +642,7 @@ * validating same-origin/tab scope. * @param {!string} sourceUrn Media source to render. * @param {!string} presentationId Presentation ID to join. - * @param {!string} origin Origin of site requesting join. + * @param {!originMojom.Origin} origin Origin of site requesting join. * @param {!number} tabId ID of tab requesting join. * @param {!TimeDelta} timeout If positive, the timeout duration for the * request. Otherwise, the default duration will be used. @@ -618,7 +657,7 @@ incognito) { this.handlers_.onBeforeInvokeHandler(); return this.handlers_.joinRoute( - sourceUrn, presentationId, origin, tabId, + sourceUrn, presentationId, mojoOriginToString_(origin), tabId, Math.floor(timeout.microseconds / 1000), incognito) .then(function(route) { return toSuccessRouteResponse_(route); @@ -635,7 +674,7 @@ * @param {!string} sourceUrn Media source to render. * @param {!string} routeId Route ID to join. * @param {!string} presentationId Presentation ID to join. - * @param {!string} origin Origin of site requesting join. + * @param {!originMojom.Origin} origin Origin of site requesting join. * @param {!number} tabId ID of tab requesting join. * @param {!TimeDelta} timeout If positive, the timeout duration for the * request. Otherwise, the default duration will be used. @@ -650,7 +689,7 @@ timeout, incognito) { this.handlers_.onBeforeInvokeHandler(); return this.handlers_.connectRouteByRouteId( - sourceUrn, routeId, presentationId, origin, tabId, + sourceUrn, routeId, presentationId, mojoOriginToString_(origin), tabId, Math.floor(timeout.microseconds / 1000), incognito) .then(function(route) { return toSuccessRouteResponse_(route);
diff --git a/gin/BUILD.gn b/gin/BUILD.gn index 5f0dc5d1..6ad0eac4 100644 --- a/gin/BUILD.gn +++ b/gin/BUILD.gn
@@ -103,11 +103,6 @@ "//base/third_party/dynamic_annotations", "//crypto", ] - if (v8_use_external_startup_data && is_win) { - public_deps += [ ":gin_v8_snapshot_fingerprint" ] - sources += [ "$target_gen_dir/v8_snapshot_fingerprint.cc" ] - defines += [ "V8_VERIFY_EXTERNAL_STARTUP_DATA" ] - } if (is_mac) { libs = [ "CoreFoundation.framework" ] @@ -116,36 +111,6 @@ configs += [ "//v8:external_startup_data" ] } -if (v8_use_external_startup_data) { - action("gin_v8_snapshot_fingerprint") { - script = "//gin/fingerprint/fingerprint_v8_snapshot.py" - - snapshot_file = "$root_out_dir/snapshot_blob.bin" - natives_file = "$root_out_dir/natives_blob.bin" - output_file = "$target_gen_dir/v8_snapshot_fingerprint.cc" - - args = [ - "--snapshot_file", - rebase_path(snapshot_file, root_build_dir), - "--natives_file", - rebase_path(natives_file, root_build_dir), - "--output_file", - rebase_path(output_file, root_build_dir), - ] - inputs = [ - snapshot_file, - natives_file, - ] - outputs = [ - output_file, - ] - - deps = [ - "//v8", - ] - } -} - executable("gin_shell") { sources = [ "shell/gin_main.cc",
diff --git a/gin/fingerprint/fingerprint_v8_snapshot.py b/gin/fingerprint/fingerprint_v8_snapshot.py deleted file mode 100755 index d1f70923..0000000 --- a/gin/fingerprint/fingerprint_v8_snapshot.py +++ /dev/null
@@ -1,86 +0,0 @@ -#!/usr/bin/env python -# -# 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. - -"""Fingerprints the V8 snapshot blob files. - -Constructs a SHA256 fingerprint of the V8 natives and snapshot blob files and -creates a .cc file which includes these fingerprint as variables. -""" - -import hashlib -import optparse -import os -import sys - -_HEADER = """// 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. - -// This file was generated by fingerprint_v8_snapshot.py. - -namespace gin { -""" - -_FOOTER = """ -} // namespace gin -""" - - -def FingerprintFile(file_path): - input_file = open(file_path, 'rb') - sha256 = hashlib.sha256() - while True: - block = input_file.read(sha256.block_size) - if not block: - break - sha256.update(block) - return sha256.digest() - - -def WriteFingerprint(output_file, variable_name, fingerprint): - output_file.write('\nextern const unsigned char %s[] = { ' % variable_name) - for byte in fingerprint: - output_file.write(str(ord(byte)) + ', ') - output_file.write('};\n') - - -def WriteOutputFile(natives_fingerprint, - snapshot_fingerprint, - output_file_path): - output_dir_path = os.path.dirname(output_file_path) - if not os.path.exists(output_dir_path): - os.makedirs(output_dir_path) - output_file = open(output_file_path, 'w') - - output_file.write(_HEADER) - WriteFingerprint(output_file, 'g_natives_fingerprint', natives_fingerprint) - output_file.write('\n') - WriteFingerprint(output_file, 'g_snapshot_fingerprint', snapshot_fingerprint) - output_file.write(_FOOTER) - - -def main(): - parser = optparse.OptionParser() - - parser.add_option('--snapshot_file', - help='The input V8 snapshot blob file path.') - parser.add_option('--natives_file', - help='The input V8 natives blob file path.') - parser.add_option('--output_file', - help='The path for the output cc file which will be write.') - - options, _ = parser.parse_args() - - natives_fingerprint = FingerprintFile(options.natives_file) - snapshot_fingerprint = FingerprintFile(options.snapshot_file) - WriteOutputFile( - natives_fingerprint, snapshot_fingerprint, options.output_file) - - return 0 - - -if __name__ == '__main__': - sys.exit(main())
diff --git a/gin/v8_initializer.cc b/gin/v8_initializer.cc index 9abea438..4131f04 100644 --- a/gin/v8_initializer.cc +++ b/gin/v8_initializer.cc
@@ -191,36 +191,6 @@ return opened; } -#if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) -bool VerifyV8StartupFile(base::MemoryMappedFile** file, - const unsigned char* fingerprint) { - unsigned char output[crypto::kSHA256Length]; - crypto::SHA256HashString( - base::StringPiece(reinterpret_cast<const char*>((*file)->data()), - (*file)->length()), - output, sizeof(output)); - if (!memcmp(fingerprint, output, sizeof(output))) { - return true; - } - - // TODO(oth): Remove this temporary diagnostics for http://crbug.com/501799 - uint64_t input[sizeof(output)]; - memcpy(input, fingerprint, sizeof(input)); - - base::debug::Alias(output); - base::debug::Alias(input); - - const uint64_t* o64 = reinterpret_cast<const uint64_t*>(output); - const uint64_t* f64 = reinterpret_cast<const uint64_t*>(fingerprint); - LOG(FATAL) << "Natives length " << (*file)->length() - << " H(computed) " << o64[0] << o64[1] << o64[2] << o64[3] - << " H(expected) " << f64[0] << f64[1] << f64[2] << f64[3]; - - delete *file; - *file = NULL; - return false; -} -#endif // V8_VERIFY_EXTERNAL_STARTUP_DATA #endif // V8_USE_EXTERNAL_STARTUP_DATA bool GenerateEntropy(unsigned char* buffer, size_t amount) { @@ -231,47 +201,37 @@ } // namespace #if defined(V8_USE_EXTERNAL_STARTUP_DATA) -#if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) -// Defined in gen/gin/v8_snapshot_fingerprint.cc -extern const unsigned char g_natives_fingerprint[]; -extern const unsigned char g_snapshot_fingerprint[]; -#endif // V8_VERIFY_EXTERNAL_STARTUP_DATA + +namespace { enum LoadV8FileResult { V8_LOAD_SUCCESS = 0, V8_LOAD_FAILED_OPEN, V8_LOAD_FAILED_MAP, - V8_LOAD_FAILED_VERIFY, + V8_LOAD_FAILED_VERIFY, // Deprecated. V8_LOAD_MAX_VALUE }; -static LoadV8FileResult MapVerify(const OpenedFileMap::mapped_type& file_region, -#if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) - const unsigned char* fingerprint, -#endif - base::MemoryMappedFile** mmapped_file_out) { +static LoadV8FileResult MapOpenedFile( + const OpenedFileMap::mapped_type& file_region, + base::MemoryMappedFile** mmapped_file_out) { if (file_region.first == base::kInvalidPlatformFile) return V8_LOAD_FAILED_OPEN; if (!MapV8File(file_region.first, file_region.second, mmapped_file_out)) return V8_LOAD_FAILED_MAP; -#if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) - if (!VerifyV8StartupFile(mmapped_file_out, fingerprint)) - return V8_LOAD_FAILED_VERIFY; -#endif // V8_VERIFY_EXTERNAL_STARTUP_DATA return V8_LOAD_SUCCESS; } +} // namespace + // static void V8Initializer::LoadV8Snapshot() { if (g_mapped_snapshot) return; OpenFileIfNecessary(kSnapshotFileName); - LoadV8FileResult result = MapVerify(GetOpenedFile(kSnapshotFileName), -#if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) - g_snapshot_fingerprint, -#endif - &g_mapped_snapshot); + LoadV8FileResult result = MapOpenedFile(GetOpenedFile(kSnapshotFileName), + &g_mapped_snapshot); // V8 can't start up without the source of the natives, but it can // start up (slower) without the snapshot. UMA_HISTOGRAM_ENUMERATION("V8.Initializer.LoadV8Snapshot.Result", result, @@ -283,11 +243,8 @@ return; OpenFileIfNecessary(kNativesFileName); - LoadV8FileResult result = MapVerify(GetOpenedFile(kNativesFileName), -#if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) - g_natives_fingerprint, -#endif - &g_mapped_natives); + LoadV8FileResult result = MapOpenedFile(GetOpenedFile(kNativesFileName), + &g_mapped_natives); if (result != V8_LOAD_SUCCESS) { LOG(FATAL) << "Couldn't mmap v8 natives data file, status code is " << static_cast<int>(result); @@ -314,10 +271,6 @@ LoadV8FileResult result = V8_LOAD_SUCCESS; if (!MapV8File(snapshot_pf, snapshot_region, &g_mapped_snapshot)) result = V8_LOAD_FAILED_MAP; -#if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) - if (!VerifyV8StartupFile(&g_mapped_snapshot, g_snapshot_fingerprint)) - result = V8_LOAD_FAILED_VERIFY; -#endif // V8_VERIFY_EXTERNAL_STARTUP_DATA if (result == V8_LOAD_SUCCESS) { g_opened_files.Get()[kSnapshotFileName] = std::make_pair(snapshot_pf, snapshot_region); @@ -345,11 +298,6 @@ if (!MapV8File(natives_pf, natives_region, &g_mapped_natives)) { LOG(FATAL) << "Couldn't mmap v8 natives data file"; } -#if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) - if (!VerifyV8StartupFile(&g_mapped_natives, g_natives_fingerprint)) { - LOG(FATAL) << "Couldn't verify contents of v8 natives data file"; - } -#endif // V8_VERIFY_EXTERNAL_STARTUP_DATA g_opened_files.Get()[kNativesFileName] = std::make_pair(natives_pf, natives_region); }
diff --git a/gpu/GLES2/OWNERS b/gpu/GLES2/OWNERS index cd07f4d..dbd228d 100644 --- a/gpu/GLES2/OWNERS +++ b/gpu/GLES2/OWNERS
@@ -3,3 +3,5 @@ bajones@chromium.org zmo@chromium.org vmiura@chromium.org + +# COMPONENT: Internals>GPU
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_gpu_memory_buffer_image.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_gpu_memory_buffer_image.txt deleted file mode 100644 index 93af3d9..0000000 --- a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_gpu_memory_buffer_image.txt +++ /dev/null
@@ -1,73 +0,0 @@ -Name - - CHROMIUM_gpu_memory_buffer_image - -Name Strings - - GL_CHROMIUM_gpu_memory_buffer_image - -Version - - Last Modifed Date: Sep 29, 2014 - -Dependencies - - OpenGL ES 2.0 is required. - - GL_CHROMIUM_image is required. - -Overview - - This extension provide a mechanism for creating a GpuMemoryBuffer - backed image resource. - -Issues - - None - -New Tokens - - Accepted by the <usage> parameter of CreateGpuMemoryBufferImageCHROMIUM: - - READ_WRITE_CHROMIUM 0x78F2 - -New Procedures and Functions - - GLuint CreateGpuMemoryBufferImageCHROMIUM(GLsizei width, - GLsizei height, - GLenum internalformat, - GLenum usage) - - Create a GpuMemoryBuffer backed image with width equal to <width> - and height equal to <height> and format equal to <internalformat>. - - Returns a unique identifier for the image that could be used in - subsequent operations. - - INVALID_VALUE is generated if <width> or <height> is nonpositive. - - INVALID_ENUM is generated if <internalformat> is not one of - RGB or RGBA. - - INVALID_ENUM is generated if <usage> is not READ_WRTIE_CHROMIUM. - - On OS X, driver bugs prevent the usage of memory buffers with RGB internal - format. As a workaround, the created GpuMemoryBuffer will always have - internal format RGBA. The caller is responsible for handling this - appropriately. The only support provided by this extension is that calls - that require parameter validation (such as copyTexImage2D and - copyTexSubImage2D) will perform paramter validation as if the internal - format were RGB. - -Errors - - None. - -New State - - None. - -Revision History - - 9/29/2014 Documented the extension. - 4/12/2016 Added details of OS X RGB workaround.
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_ycbcr_420v_image.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_ycbcr_420v_image.txt index c83453ec..db0957b6 100644 --- a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_ycbcr_420v_image.txt +++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_ycbcr_420v_image.txt
@@ -21,9 +21,8 @@ This extension provides a new internal image format to use when creating an image from underlying '420v' buffers. - This extension is useful in conjunction with CreateImageCHROMIUM and - CreateGpuMemoryBufferImageCHROMIUM to define the format of GpuMemoryBuffer - backing the image. + This extension is useful in conjunction with CreateImageCHROMIUM to define + the format of GpuMemoryBuffer backing the image. New Procedures and Functions @@ -35,9 +34,7 @@ New Tokens - Accepted by the <internalformat> parameter of CreateImageCHROMIUM, and - <internalformat> parameter of CreateGpuMemoryBufferImageCHROMIUM: - GL_RGB_YCBCR_420V_CHROMIUM 0x78FC + Accepted by the <internalformat> parameter of CreateImageCHROMIUM. New State
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_ycbcr_422_image.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_ycbcr_422_image.txt index 546d783..2ab489b 100644 --- a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_ycbcr_422_image.txt +++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_ycbcr_422_image.txt
@@ -21,9 +21,8 @@ This extension provides a new internal image format to use when creating an image from underlying '2vuy' buffers. - This extension is useful in conjunction with CreateImageCHROMIUM and - CreateGpuMemoryBufferImageCHROMIUM to define the format of GpuMemoryBuffer - backing the image. + This extension is useful in conjunction with CreateImageCHROMIUM to define + the format of GpuMemoryBuffer backing the image. New Procedures and Functions @@ -35,9 +34,7 @@ New Tokens - Accepted by the <internalformat> parameter of CreateImageCHROMIUM, and - <internalformat> parameter of CreateGpuMemoryBufferImageCHROMIUM: - GL_RGB_YCBCR_422_CHROMIUM 0x78FB + Accepted by the <internalformat> parameter of CreateImageCHROMIUM. New State
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_ycrcb_420_image.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_ycrcb_420_image.txt index f5ad474..c87b5e0 100644 --- a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_ycrcb_420_image.txt +++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_ycrcb_420_image.txt
@@ -21,9 +21,8 @@ This extension provides a new internal image format to use when creating an image from underlying YV12 buffers with YVU components. - This extension is useful in conjunction with CreateImageCHROMIUM and - CreateGpuMemoryBufferImageCHROMIUM to define the format of GpuMemoryBuffer - backing the image. + This extension is useful in conjunction with CreateImageCHROMIUM to define + the format of GpuMemoryBuffer backing the image. New Procedures and Functions @@ -35,9 +34,7 @@ New Tokens - Accepted by the <internalformat> parameter of CreateImageCHROMIUM, and - <internalformat> parameter of CreateGpuMemoryBufferImageCHROMIUM: - GL_RGB_YCRCB_420_CHROMIUM 0x78FA + Accepted by the <internalformat> parameter of CreateImageCHROMIUM. New State
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h index 4c174efb..99bb510 100644 --- a/gpu/GLES2/gl2chromium_autogen.h +++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -289,8 +289,6 @@ #define glGetUniformsES3CHROMIUM GLES2_GET_FUN(GetUniformsES3CHROMIUM) #define glCreateImageCHROMIUM GLES2_GET_FUN(CreateImageCHROMIUM) #define glDestroyImageCHROMIUM GLES2_GET_FUN(DestroyImageCHROMIUM) -#define glCreateGpuMemoryBufferImageCHROMIUM \ - GLES2_GET_FUN(CreateGpuMemoryBufferImageCHROMIUM) #define glDescheduleUntilFinishedCHROMIUM \ GLES2_GET_FUN(DescheduleUntilFinishedCHROMIUM) #define glGetTranslatedShaderSourceANGLE \
diff --git a/gpu/GLES2/gl2extchromium.h b/gpu/GLES2/gl2extchromium.h index db7cd632..e38949b 100644 --- a/gpu/GLES2/gl2extchromium.h +++ b/gpu/GLES2/gl2extchromium.h
@@ -94,14 +94,6 @@ GL_APIENTRYP PFNGLDESTROYIMAGECHROMIUMPROC)(GLuint image_id); #endif /* GL_CHROMIUM_image */ - /* GL_CHROMIUM_gpu_memory_buffer_image */ -#ifndef GL_CHROMIUM_gpu_memory_buffer_image -#define GL_CHROMIUM_gpu_memory_buffer_image 1 - -#ifndef GL_READ_WRITE_CHROMIUM -#define GL_READ_WRITE_CHROMIUM 0x78F2 -#endif - #ifndef GL_RGB_YCRCB_420_CHROMIUM #define GL_RGB_YCRCB_420_CHROMIUM 0x78FA #endif @@ -114,20 +106,6 @@ #define GL_RGB_YCBCR_420V_CHROMIUM 0x78FC #endif -#ifdef GL_GLEXT_PROTOTYPES -GL_APICALL GLuint GL_APIENTRY glCreateGpuMemoryBufferImageCHROMIUM( - GLsizei width, - GLsizei height, - GLenum internalformat, - GLenum usage); -#endif -typedef GLuint(GL_APIENTRYP PFNGLCREATEGPUMEMORYBUFFERIMAGECHROMIUMPROC)( - GLsizei width, - GLsizei height, - GLenum internalformat, - GLenum usage); -#endif /* GL_CHROMIUM_gpu_memory_buffer_image */ - /* GL_CHROMIUM_deschedule */ #ifndef GL_CHROMIUM_deschedule #define GL_CHROMIUM_deschedule 1
diff --git a/gpu/command_buffer/OWNERS b/gpu/command_buffer/OWNERS index 16b05676..a1c727d 100644 --- a/gpu/command_buffer/OWNERS +++ b/gpu/command_buffer/OWNERS
@@ -7,3 +7,5 @@ # GPU memory buffer tests. per-file *gpu_memory_buffer*=reveman@chromium.org + +# COMPONENT: Internals>GPU
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index bbb6037..7d04b730 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -2146,12 +2146,6 @@ 'GL_RGBA', ], }, - 'ImageUsage': { - 'type': 'GLenum', - 'valid': [ - 'GL_READ_WRITE_CHROMIUM', - ], - }, 'UniformParameter': { 'type': 'GLenum', 'is_complete': True, @@ -2670,14 +2664,6 @@ 'extension': "CHROMIUM_image", 'trace_level': 1, }, - 'CreateGpuMemoryBufferImageCHROMIUM': { - 'type': 'NoCommand', - 'cmd_args': - 'GLsizei width, GLsizei height, GLenum internalformat, GLenum usage', - 'result': ['GLuint'], - 'extension': "CHROMIUM_gpu_memory_buffer_image", - 'trace_level': 1, - }, 'DescheduleUntilFinishedCHROMIUM': { 'type': 'Custom', 'decoder_func': 'DoDescheduleUntilFinishedCHROMIUM',
diff --git a/gpu/command_buffer/client/client_test_helper.h b/gpu/command_buffer/client/client_test_helper.h index 9df3e6ba..31756c35 100644 --- a/gpu/command_buffer/client/client_test_helper.h +++ b/gpu/command_buffer/client/client_test_helper.h
@@ -102,11 +102,6 @@ size_t height, unsigned internalformat)); MOCK_METHOD1(DestroyImage, void(int32_t id)); - MOCK_METHOD4(CreateGpuMemoryBufferImage, - int32_t(size_t width, - size_t height, - unsigned internalformat, - unsigned usage)); MOCK_METHOD2(SignalQuery, void(uint32_t query, const base::Closure& callback)); MOCK_METHOD1(CreateStreamTexture, uint32_t(uint32_t));
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h index 1cca3837..de9c7da4 100644 --- a/gpu/command_buffer/client/gles2_c_lib_autogen.h +++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -1313,14 +1313,6 @@ void GL_APIENTRY GLES2DestroyImageCHROMIUM(GLuint image_id) { gles2::GetGLContext()->DestroyImageCHROMIUM(image_id); } -GLuint GL_APIENTRY -GLES2CreateGpuMemoryBufferImageCHROMIUM(GLsizei width, - GLsizei height, - GLenum internalformat, - GLenum usage) { - return gles2::GetGLContext()->CreateGpuMemoryBufferImageCHROMIUM( - width, height, internalformat, usage); -} void GL_APIENTRY GLES2DescheduleUntilFinishedCHROMIUM() { gles2::GetGLContext()->DescheduleUntilFinishedCHROMIUM(); } @@ -2732,11 +2724,6 @@ reinterpret_cast<GLES2FunctionPointer>(glDestroyImageCHROMIUM), }, { - "glCreateGpuMemoryBufferImageCHROMIUM", - reinterpret_cast<GLES2FunctionPointer>( - glCreateGpuMemoryBufferImageCHROMIUM), - }, - { "glDescheduleUntilFinishedCHROMIUM", reinterpret_cast<GLES2FunctionPointer>( glDescheduleUntilFinishedCHROMIUM),
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index b2614fe..8b272ded 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -3772,8 +3772,7 @@ str += std::string(str.empty() ? "" : " ") + "GL_EXT_unpack_subimage " "GL_CHROMIUM_map_sub " - "GL_CHROMIUM_image " - "GL_CHROMIUM_gpu_memory_buffer_image"; + "GL_CHROMIUM_image"; if (capabilities_.future_sync_points) str += " GL_CHROMIUM_future_sync_point"; } @@ -6199,20 +6198,6 @@ } } -bool CreateGpuMemoryBufferValidInternalFormat(GLenum internalformat) { - switch (internalformat) { - case GL_RGB: - case GL_RGBA: - return true; - default: - return false; - } -} - -bool ValidImageUsage(GLenum usage) { - return usage == GL_READ_WRITE_CHROMIUM; -} - } // namespace GLuint GLES2Implementation::CreateImageCHROMIUMHelper(ClientBuffer buffer, @@ -6277,69 +6262,6 @@ CheckGLError(); } -GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUMHelper( - GLsizei width, - GLsizei height, - GLenum internalformat, - GLenum usage) { - if (width <= 0) { - SetGLError( - GL_INVALID_VALUE, "glCreateGpuMemoryBufferImageCHROMIUM", "width <= 0"); - return 0; - } - - if (height <= 0) { - SetGLError(GL_INVALID_VALUE, - "glCreateGpuMemoryBufferImageCHROMIUM", - "height <= 0"); - return 0; - } - - if (!CreateGpuMemoryBufferValidInternalFormat(internalformat)) { - SetGLError(GL_INVALID_VALUE, - "glCreateGpuMemoryBufferImageCHROMIUM", - "invalid format"); - return 0; - } - - if (!ValidImageUsage(usage)) { - SetGLError(GL_INVALID_VALUE, - "glCreateGpuMemoryBufferImageCHROMIUM", - "invalid usage"); - return 0; - } - - // Flush the command stream to ensure ordering in case the newly - // returned image_id has recently been in use with a different buffer. - helper_->CommandBufferHelper::Flush(); - int32_t image_id = gpu_control_->CreateGpuMemoryBufferImage( - width, height, internalformat, usage); - if (image_id < 0) { - SetGLError(GL_OUT_OF_MEMORY, - "glCreateGpuMemoryBufferImageCHROMIUM", - "image_id < 0"); - return 0; - } - return image_id; -} - -GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUM( - GLsizei width, - GLsizei height, - GLenum internalformat, - GLenum usage) { - GPU_CLIENT_SINGLE_THREAD_CHECK(); - GPU_CLIENT_LOG("[" << GetLogPrefix() - << "] glCreateGpuMemoryBufferImageCHROMIUM(" << width - << ", " << height << ", " - << GLES2Util::GetStringImageInternalFormat(internalformat) - << ", " << GLES2Util::GetStringImageUsage(usage) << ")"); - GLuint image_id = CreateGpuMemoryBufferImageCHROMIUMHelper( - width, height, internalformat, usage); - CheckGLError(); - return image_id; -} - bool GLES2Implementation::ValidateSize(const char* func, GLsizeiptr size) { if (size < 0) { SetGLError(GL_INVALID_VALUE, func, "size < 0");
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h index 953e11a..a0f2d12 100644 --- a/gpu/command_buffer/client/gles2_implementation.h +++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -534,10 +534,6 @@ GLsizei height, GLenum internalformat); void DestroyImageCHROMIUMHelper(GLuint image_id); - GLuint CreateGpuMemoryBufferImageCHROMIUMHelper(GLsizei width, - GLsizei height, - GLenum internalformat, - GLenum usage); // Helper for GetVertexAttrib bool GetVertexAttribHelper(GLuint index, GLenum pname, uint32_t* param);
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h index dd4206c..e67c89a 100644 --- a/gpu/command_buffer/client/gles2_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -924,11 +924,6 @@ void DestroyImageCHROMIUM(GLuint image_id) override; -GLuint CreateGpuMemoryBufferImageCHROMIUM(GLsizei width, - GLsizei height, - GLenum internalformat, - GLenum usage) override; - void DescheduleUntilFinishedCHROMIUM() override; void GetTranslatedShaderSourceANGLE(GLuint shader,
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc index fbf35d2..48484912 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest.cc +++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -3203,8 +3203,7 @@ "foobar " "GL_EXT_unpack_subimage " "GL_CHROMIUM_map_sub " - "GL_CHROMIUM_image " - "GL_CHROMIUM_gpu_memory_buffer_image"; + "GL_CHROMIUM_image"; const char kBad = 0x12; struct Cmds { cmd::SetBucketSize set_bucket_size1; @@ -4609,43 +4608,6 @@ EXPECT_EQ(0, lost_count); } -TEST_F(GLES2ImplementationManualInitTest, LoseContextOnOOM) { - ContextInitOptions init_options; - init_options.lose_context_when_out_of_memory = true; - ASSERT_TRUE(Initialize(init_options)); - - struct Cmds { - cmds::LoseContextCHROMIUM cmd; - }; - - GLsizei max = std::numeric_limits<GLsizei>::max(); - EXPECT_CALL(*gpu_control_, CreateGpuMemoryBufferImage(max, max, _, _)) - .WillOnce(Return(-1)); - gl_->CreateGpuMemoryBufferImageCHROMIUM(max, max, GL_RGBA, - GL_READ_WRITE_CHROMIUM); - // The context should be lost. - Cmds expected; - expected.cmd.Init(GL_GUILTY_CONTEXT_RESET_ARB, GL_UNKNOWN_CONTEXT_RESET_ARB); - EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); -} - -TEST_F(GLES2ImplementationManualInitTest, NoLoseContextOnOOM) { - ContextInitOptions init_options; - ASSERT_TRUE(Initialize(init_options)); - - struct Cmds { - cmds::LoseContextCHROMIUM cmd; - }; - - GLsizei max = std::numeric_limits<GLsizei>::max(); - EXPECT_CALL(*gpu_control_, CreateGpuMemoryBufferImage(max, max, _, _)) - .WillOnce(Return(-1)); - gl_->CreateGpuMemoryBufferImageCHROMIUM(max, max, GL_RGBA, - GL_READ_WRITE_CHROMIUM); - // The context should not be lost. - EXPECT_TRUE(NoCommandsWritten()); -} - TEST_F(GLES2ImplementationManualInitTest, FailInitOnBGRMismatch1) { ContextInitOptions init_options; init_options.bind_generates_resource_client = false;
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h index 534ed6d..ba015e1 100644 --- a/gpu/command_buffer/client/gles2_interface_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -675,10 +675,6 @@ GLsizei height, GLenum internalformat) = 0; virtual void DestroyImageCHROMIUM(GLuint image_id) = 0; -virtual GLuint CreateGpuMemoryBufferImageCHROMIUM(GLsizei width, - GLsizei height, - GLenum internalformat, - GLenum usage) = 0; virtual void DescheduleUntilFinishedCHROMIUM() = 0; virtual void GetTranslatedShaderSourceANGLE(GLuint shader, GLsizei bufsize,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h index a30654b3..37f34640 100644 --- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -654,10 +654,6 @@ GLsizei height, GLenum internalformat) override; void DestroyImageCHROMIUM(GLuint image_id) override; -GLuint CreateGpuMemoryBufferImageCHROMIUM(GLsizei width, - GLsizei height, - GLenum internalformat, - GLenum usage) override; void DescheduleUntilFinishedCHROMIUM() override; void GetTranslatedShaderSourceANGLE(GLuint shader, GLsizei bufsize,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h index 81ddb82..dec13b3 100644 --- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -898,13 +898,6 @@ return 0; } void GLES2InterfaceStub::DestroyImageCHROMIUM(GLuint /* image_id */) {} -GLuint GLES2InterfaceStub::CreateGpuMemoryBufferImageCHROMIUM( - GLsizei /* width */, - GLsizei /* height */, - GLenum /* internalformat */, - GLenum /* usage */) { - return 0; -} void GLES2InterfaceStub::DescheduleUntilFinishedCHROMIUM() {} void GLES2InterfaceStub::GetTranslatedShaderSourceANGLE(GLuint /* shader */, GLsizei /* bufsize */,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h index fcdac4c..bfbe6394 100644 --- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -654,10 +654,6 @@ GLsizei height, GLenum internalformat) override; void DestroyImageCHROMIUM(GLuint image_id) override; -GLuint CreateGpuMemoryBufferImageCHROMIUM(GLsizei width, - GLsizei height, - GLenum internalformat, - GLenum usage) override; void DescheduleUntilFinishedCHROMIUM() override; void GetTranslatedShaderSourceANGLE(GLuint shader, GLsizei bufsize,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h index aa48709f..f06bcd6 100644 --- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h +++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -1913,17 +1913,6 @@ gl_->DestroyImageCHROMIUM(image_id); } -GLuint GLES2TraceImplementation::CreateGpuMemoryBufferImageCHROMIUM( - GLsizei width, - GLsizei height, - GLenum internalformat, - GLenum usage) { - TRACE_EVENT_BINARY_EFFICIENT0( - "gpu", "GLES2Trace::CreateGpuMemoryBufferImageCHROMIUM"); - return gl_->CreateGpuMemoryBufferImageCHROMIUM(width, height, internalformat, - usage); -} - void GLES2TraceImplementation::DescheduleUntilFinishedCHROMIUM() { TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DescheduleUntilFinishedCHROMIUM");
diff --git a/gpu/command_buffer/client/gpu_control.h b/gpu/command_buffer/client/gpu_control.h index 6242989..6b7bdd5 100644 --- a/gpu/command_buffer/client/gpu_control.h +++ b/gpu/command_buffer/client/gpu_control.h
@@ -48,13 +48,6 @@ // Destroy an image. The ID must be positive. virtual void DestroyImage(int32_t id) = 0; - // Create a gpu memory buffer backed image with the given dimensions and - // format for |usage|. Returns its ID or -1 on error. - virtual int32_t CreateGpuMemoryBufferImage(size_t width, - size_t height, - unsigned internalformat, - unsigned usage) = 0; - // Runs |callback| when a query created via glCreateQueryEXT() has cleared // passed the glEndQueryEXT() point. virtual void SignalQuery(uint32_t query, const base::Closure& callback) = 0;
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt index be80613..e0db0f5 100644 --- a/gpu/command_buffer/cmd_buffer_functions.txt +++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -276,7 +276,6 @@ GL_APICALL void GL_APIENTRY glGetUniformsES3CHROMIUM (GLidProgram program, GLsizeiNotNegative bufsize, GLsizei* size, void* info); GL_APICALL GLuint GL_APIENTRY glCreateImageCHROMIUM (ClientBuffer buffer, GLsizei width, GLsizei height, GLenum internalformat); GL_APICALL void GL_APIENTRY glDestroyImageCHROMIUM (GLuint image_id); -GL_APICALL GLuint GL_APIENTRY glCreateGpuMemoryBufferImageCHROMIUM (GLsizei width, GLsizei height, GLenum internalformat, GLenum usage); GL_APICALL void GL_APIENTRY glDescheduleUntilFinishedCHROMIUM (void); GL_APICALL void GL_APIENTRY glGetTranslatedShaderSourceANGLE (GLidShader shader, GLsizeiNotNegative bufsize, GLsizeiOptional* length, char* source); GL_APICALL void GL_APIENTRY glPostSubBufferCHROMIUM (GLint x, GLint y, GLint width, GLint height);
diff --git a/gpu/command_buffer/common/capabilities.h b/gpu/command_buffer/common/capabilities.h index a456ce5..5d24619 100644 --- a/gpu/command_buffer/common/capabilities.h +++ b/gpu/command_buffer/common/capabilities.h
@@ -157,7 +157,7 @@ // When this parameter is true, a CHROMIUM image created with RGB format will // actually have RGBA format. The client is responsible for handling most of // the complexities associated with this. See - // gpu/GLES2/extensions/CHROMIUM/CHROMIUM_gpu_memory_buffer_image.txt for more + // gpu/GLES2/extensions/CHROMIUM/CHROMIUM_image.txt for more // details. bool chromium_image_rgb_emulation = false;
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.cc b/gpu/command_buffer/common/gles2_cmd_utils.cc index 7d97aeb6..6eb9b8e 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils.cc +++ b/gpu/command_buffer/common/gles2_cmd_utils.cc
@@ -1309,6 +1309,18 @@ } } +GLint GLES2Util::GetColorEncodingFromInternalFormat(uint32_t internalformat) { + switch (internalformat) { + case GL_SRGB_EXT: + case GL_SRGB_ALPHA_EXT: + case GL_SRGB8: + case GL_SRGB8_ALPHA8: + return GL_SRGB; + default: + return GL_LINEAR; + } +} + void GLES2Util::GetColorFormatComponentSizes( uint32_t internal_format, uint32_t type, int* r, int* g, int* b, int* a) { DCHECK(r && g && b && a);
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.h b/gpu/command_buffer/common/gles2_cmd_utils.h index 8d0f16ba..969a724 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils.h +++ b/gpu/command_buffer/common/gles2_cmd_utils.h
@@ -243,8 +243,11 @@ static bool IsIntegerFormat(uint32_t internal_format); static bool IsFloatFormat(uint32_t internal_format); static uint32_t ConvertToSizedFormat(uint32_t format, uint32_t type); - static bool IsSizedColorFormat(uint32_t internal_format); + + // Infer color encoding from internalformat + static int GetColorEncodingFromInternalFormat(uint32_t internalformat); + static void GetColorFormatComponentSizes( uint32_t internal_format, uint32_t type, int* r, int* g, int* b, int* a);
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h index 1775e7d..ae61c26c4 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
@@ -41,7 +41,6 @@ static std::string GetStringHintMode(uint32_t value); static std::string GetStringHintTarget(uint32_t value); static std::string GetStringImageInternalFormat(uint32_t value); -static std::string GetStringImageUsage(uint32_t value); static std::string GetStringIndexType(uint32_t value); static std::string GetStringIndexedBufferTarget(uint32_t value); static std::string GetStringIndexedGLState(uint32_t value);
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h index 15467c9..104637b 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
@@ -643,9 +643,6 @@ 0x78EF, "GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM", }, { - 0x78F2, "GL_READ_WRITE_CHROMIUM", - }, - { 0x78FA, "GL_RGB_YCRCB_420_CHROMIUM", }, { @@ -4000,14 +3997,6 @@ arraysize(string_table), value); } -std::string GLES2Util::GetStringImageUsage(uint32_t value) { - static const EnumToString string_table[] = { - {GL_READ_WRITE_CHROMIUM, "GL_READ_WRITE_CHROMIUM"}, - }; - return GLES2Util::GetQualifiedEnumString(string_table, - arraysize(string_table), value); -} - std::string GLES2Util::GetStringIndexType(uint32_t value) { static const EnumToString string_table[] = { {GL_UNSIGNED_BYTE, "GL_UNSIGNED_BYTE"},
diff --git a/gpu/command_buffer/common/gpu_memory_buffer_support.h b/gpu/command_buffer/common/gpu_memory_buffer_support.h index 7539de3..ad87b1d7 100644 --- a/gpu/command_buffer/common/gpu_memory_buffer_support.h +++ b/gpu/command_buffer/common/gpu_memory_buffer_support.h
@@ -15,7 +15,7 @@ struct Capabilities; // Returns a valid GpuMemoryBuffer format given a valid internalformat as -// defined by CHROMIUM_gpu_memory_buffer_image. +// defined by CHROMIUM_image. GPU_EXPORT gfx::BufferFormat DefaultBufferFormatForImageFormat( unsigned internalformat);
diff --git a/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc b/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc index ae6ad70..fa3f33e3 100644 --- a/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc +++ b/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc
@@ -256,10 +256,41 @@ if (do_copy) { ApplyCMAAEffectTexture(source_texture, rgba8_texture_, do_copy); + // Source format for DoCopySubTexture is always GL_RGBA8. + CopyTextureMethod method = DIRECT_COPY; + bool copy_tex_image_format_valid = + !GLES2Util::IsIntegerFormat(internal_format) && + GLES2Util::GetColorEncodingFromInternalFormat(internal_format) != + GL_SRGB && + internal_format != GL_BGRA_EXT && internal_format != GL_BGRA8_EXT; + if (GLES2Util::IsSizedColorFormat(internal_format)) { + int dr, dg, db, da; + GLES2Util::GetColorFormatComponentSizes(internal_format, 0, &dr, &dg, + &db, &da); + if ((dr > 0 && dr != 8) || (dg > 0 && dg != 8) || + (db > 0 && db != 8) || (da > 0 && da != 8)) { + copy_tex_image_format_valid = false; + } + } + if (!copy_tex_image_format_valid) + method = DIRECT_DRAW; + bool color_renderable = Texture::ColorRenderable( + decoder->GetFeatureInfo(), internal_format, false); +#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) + // glDrawArrays is faster than glCopyTexSubImage2D on IA Mesa driver, + // although opposite in Android. + // TODO(dshwang): After Mesa fixes this issue, remove this hack. + // https://bugs.freedesktop.org/show_bug.cgi?id=98478, crbug.com/535198. + if (color_renderable) + method = DIRECT_DRAW; +#endif + if (method == DIRECT_DRAW && !color_renderable) + method = DRAW_AND_COPY; + copier->DoCopySubTexture( decoder, GL_TEXTURE_2D, rgba8_texture_, 0, GL_RGBA8, GL_TEXTURE_2D, source_texture, 0, internal_format, 0, 0, 0, 0, width_, height_, - width_, height_, width_, height_, false, false, false, DIRECT_DRAW); + width_, height_, width_, height_, false, false, false, method); } else { ApplyCMAAEffectTexture(source_texture, source_texture, do_copy); }
diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc index e3c9d86..bbfdda1 100644 --- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc +++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
@@ -796,21 +796,13 @@ bool premultiply_alpha, bool unpremultiply_alpha, CopyTextureMethod method) { - bool use_gl_copy_tex_sub_image_2d = true; -#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) - // glDrawArrays is faster than glCopyTexSubImage2D on IA Mesa driver, - // although opposite in Android. - // TODO(dshwang): After Mesa fixes this issue, remove this hack. - // https://bugs.freedesktop.org/show_bug.cgi?id=98478 crbug.com/535198 - use_gl_copy_tex_sub_image_2d = false; -#endif bool premultiply_alpha_change = premultiply_alpha ^ unpremultiply_alpha; GLenum dest_binding_target = gpu::gles2::GLES2Util::GLFaceTargetToTextureTarget(dest_target); // GL_TEXTURE_RECTANGLE_ARB on FBO is supported by OpenGL, not GLES2, // so restrict this to GL_TEXTURE_2D and GL_TEXTURE_CUBE_MAP. - if (use_gl_copy_tex_sub_image_2d && source_target == GL_TEXTURE_2D && + if (source_target == GL_TEXTURE_2D && (dest_binding_target == GL_TEXTURE_2D || dest_binding_target == GL_TEXTURE_CUBE_MAP) && !flip_y && !premultiply_alpha_change && method == DIRECT_COPY) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 3140d6f5..ca955da 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -1295,9 +1295,6 @@ // Returns: true if glEnable/glDisable should actually be called. bool SetCapabilityState(GLenum cap, bool enabled); - // Infer color encoding from internalformat - static GLint GetColorEncodingFromInternalFormat(GLenum internalformat); - // Check that the currently bound read framebuffer's color image // isn't the target texture of the glCopyTex{Sub}Image{2D|3D}. bool FormsTextureCopyingFeedbackLoop( @@ -4417,19 +4414,6 @@ return valid; } -GLint GLES2DecoderImpl::GetColorEncodingFromInternalFormat( - GLenum internalformat) { - switch (internalformat) { - case GL_SRGB_EXT: - case GL_SRGB_ALPHA_EXT: - case GL_SRGB8: - case GL_SRGB8_ALPHA8: - return GL_SRGB; - default: - return GL_LINEAR; - } -} - bool GLES2DecoderImpl::FormsTextureCopyingFeedbackLoop( TextureRef* texture, GLint level, GLint layer) { Framebuffer* framebuffer = GetBoundReadFramebuffer(); @@ -6230,8 +6214,8 @@ bool enable_srgb = 0; if (target == GL_TEXTURE_2D) { tex->GetLevelType(target, tex->base_level(), &type, &internal_format); - enable_srgb = - GetColorEncodingFromInternalFormat(internal_format) == GL_SRGB; + enable_srgb = GLES2Util::GetColorEncodingFromInternalFormat( + internal_format) == GL_SRGB; } if (enable_srgb && feature_info_->feature_flags().desktop_srgb_support) { state_.EnableDisableFramebufferSRGB(enable_srgb); @@ -8051,8 +8035,8 @@ GLenum src_internal_format = GetBoundReadFramebufferInternalFormat(); GLenum src_type = GetBoundReadFramebufferTextureType(); - bool read_buffer_has_srgb = - GetColorEncodingFromInternalFormat(src_internal_format) == GL_SRGB; + bool read_buffer_has_srgb = GLES2Util::GetColorEncodingFromInternalFormat( + src_internal_format) == GL_SRGB; bool draw_buffers_has_srgb = false; if ((mask & GL_COLOR_BUFFER_BIT) != 0) { bool is_src_signed_int = @@ -8084,7 +8068,7 @@ if (!src_internal_format) { read_framebuffer_miss_image = true; } - if (GetColorEncodingFromInternalFormat(dst_format) == GL_SRGB) + if (GLES2Util::GetColorEncodingFromInternalFormat(dst_format) == GL_SRGB) draw_buffers_has_srgb = true; if (read_buffer_samples > 0 && (src_sized_format != @@ -13964,15 +13948,16 @@ return false; } if (feature_info_->IsWebGL2OrES3Context()) { - GLint color_encoding = GetColorEncodingFromInternalFormat(read_format); + GLint color_encoding = + GLES2Util::GetColorEncodingFromInternalFormat(read_format); bool float_mismatch = feature_info_->ext_color_buffer_float_available() ? (GLES2Util::IsIntegerFormat(internal_format) != GLES2Util::IsIntegerFormat(read_format)) : GLES2Util::IsFloatFormat(internal_format); - if (color_encoding != GetColorEncodingFromInternalFormat(internal_format) || - float_mismatch || - (GLES2Util::IsSignedIntegerFormat(internal_format) != - GLES2Util::IsSignedIntegerFormat(read_format)) || + if (color_encoding != + GLES2Util::GetColorEncodingFromInternalFormat(internal_format) || + float_mismatch || (GLES2Util::IsSignedIntegerFormat(internal_format) != + GLES2Util::IsSignedIntegerFormat(read_format)) || (GLES2Util::IsUnsignedIntegerFormat(internal_format) != GLES2Util::IsUnsignedIntegerFormat(read_format))) { *output_error_msg = std::string("incompatible format"); @@ -16471,8 +16456,10 @@ if (feature_info_->feature_flags().desktop_srgb_support) { bool enable_framebuffer_srgb = - GetColorEncodingFromInternalFormat(source_internal_format) == GL_SRGB || - GetColorEncodingFromInternalFormat(internal_format) == GL_SRGB; + GLES2Util::GetColorEncodingFromInternalFormat(source_internal_format) == + GL_SRGB || + GLES2Util::GetColorEncodingFromInternalFormat(internal_format) == + GL_SRGB; state_.EnableDisableFramebufferSRGB(enable_framebuffer_srgb); } @@ -16718,6 +16705,17 @@ return; } +#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) + // glDrawArrays is faster than glCopyTexSubImage2D on IA Mesa driver, + // although opposite in Android. + // TODO(dshwang): After Mesa fixes this issue, remove this hack. + // https://bugs.freedesktop.org/show_bug.cgi?id=98478, crbug.com/535198. + if (Texture::ColorRenderable(GetFeatureInfo(), dest_internal_format, false) && + method == DIRECT_COPY) { + method = DIRECT_DRAW; + } +#endif + // Draw to a fbo attaching level 0 of an intermediate texture, // then copy from the fbo to dest texture level with glCopyTexImage2D. // For WebGL 1.0 or OpenGL ES 2.0, DIRECT_DRAW path isn't available for @@ -16738,8 +16736,10 @@ if (feature_info_->feature_flags().desktop_srgb_support) { bool enable_framebuffer_srgb = - GetColorEncodingFromInternalFormat(source_internal_format) == GL_SRGB || - GetColorEncodingFromInternalFormat(dest_internal_format) == GL_SRGB; + GLES2Util::GetColorEncodingFromInternalFormat(source_internal_format) == + GL_SRGB || + GLES2Util::GetColorEncodingFromInternalFormat(dest_internal_format) == + GL_SRGB; state_.EnableDisableFramebufferSRGB(enable_framebuffer_srgb); }
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h index 2be3bab..408759a 100644 --- a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
@@ -131,7 +131,6 @@ ValueValidator<GLenum> hint_target; ValueValidator<GLenum> image_internal_format; -ValueValidator<GLenum> image_usage; ValueValidator<GLenum> index_type; class IndexedBufferTargetValidator { public:
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h index 48ef127d..c5b581a 100644 --- a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
@@ -471,10 +471,6 @@ GL_RGBA, }; -static const GLenum valid_image_usage_table[] = { - GL_READ_WRITE_CHROMIUM, -}; - static const GLenum valid_index_type_table[] = { GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, }; @@ -1387,7 +1383,6 @@ hint_target(valid_hint_target_table, arraysize(valid_hint_target_table)), image_internal_format(valid_image_internal_format_table, arraysize(valid_image_internal_format_table)), - image_usage(valid_image_usage_table, arraysize(valid_image_usage_table)), index_type(valid_index_type_table, arraysize(valid_index_type_table)), pixel_store(valid_pixel_store_table, arraysize(valid_pixel_store_table)), pixel_type(valid_pixel_type_table, arraysize(valid_pixel_type_table)),
diff --git a/gpu/command_buffer/tests/gl_copy_tex_image_2d_workaround_unittest.cc b/gpu/command_buffer/tests/gl_copy_tex_image_2d_workaround_unittest.cc index 050fc42c..5ac0567 100644 --- a/gpu/command_buffer/tests/gl_copy_tex_image_2d_workaround_unittest.cc +++ b/gpu/command_buffer/tests/gl_copy_tex_image_2d_workaround_unittest.cc
@@ -117,8 +117,10 @@ glBindTexture(source_target, source_texture); glTexParameteri(source_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(source_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - GLuint image_id = glCreateGpuMemoryBufferImageCHROMIUM( - width, height, GL_RGBA, GL_READ_WRITE_CHROMIUM); + std::unique_ptr<gfx::GpuMemoryBuffer> buffer(gl_.CreateGpuMemoryBuffer( + gfx::Size(width, height), gfx::BufferFormat::RGBA_8888)); + GLuint image_id = + glCreateImageCHROMIUM(buffer->AsClientBuffer(), width, height, GL_RGBA); ASSERT_NE(0u, image_id); glBindTexImage2DCHROMIUM(source_target, image_id);
diff --git a/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc b/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc index cdaaab26..5be1671 100644 --- a/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc +++ b/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc
@@ -300,8 +300,10 @@ void CreateBackingForTexture(GLenum target, GLsizei width, GLsizei height) { if (target == GL_TEXTURE_RECTANGLE_ARB) { - GLuint image_id = glCreateGpuMemoryBufferImageCHROMIUM( - width, height, GL_RGBA, GL_READ_WRITE_CHROMIUM); + std::unique_ptr<gfx::GpuMemoryBuffer> buffer(gl_.CreateGpuMemoryBuffer( + gfx::Size(width, height), gfx::BufferFormat::RGBA_8888)); + GLuint image_id = glCreateImageCHROMIUM(buffer->AsClientBuffer(), width, + height, GL_RGBA); glBindTexImage2DCHROMIUM(target, image_id); } else { glTexImage2D(target, 0, GL_RGBA, width, height, 0, GL_RGBA,
diff --git a/gpu/command_buffer/tests/gl_iosurface_readback_workaround_unittest.cc b/gpu/command_buffer/tests/gl_iosurface_readback_workaround_unittest.cc index ab176e9..2cae72ef 100644 --- a/gpu/command_buffer/tests/gl_iosurface_readback_workaround_unittest.cc +++ b/gpu/command_buffer/tests/gl_iosurface_readback_workaround_unittest.cc
@@ -51,8 +51,10 @@ glBindTexture(source_target, source_texture); glTexParameteri(source_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(source_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - GLuint image_id = glCreateGpuMemoryBufferImageCHROMIUM( - width, height, GL_RGBA, GL_READ_WRITE_CHROMIUM); + std::unique_ptr<gfx::GpuMemoryBuffer> buffer(gl_.CreateGpuMemoryBuffer( + gfx::Size(width, height), gfx::BufferFormat::RGBA_8888)); + GLuint image_id = + glCreateImageCHROMIUM(buffer->AsClientBuffer(), width, height, GL_RGBA); ASSERT_NE(0u, image_id); glBindTexImage2DCHROMIUM(source_target, image_id);
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc index 49db8c8..1129bd9 100644 --- a/gpu/command_buffer/tests/gl_manager.cc +++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -582,16 +582,6 @@ return new_id; } -int32_t GLManager::CreateGpuMemoryBufferImage(size_t width, - size_t height, - unsigned internalformat, - unsigned usage) { - DCHECK_EQ(usage, static_cast<unsigned>(GL_READ_WRITE_CHROMIUM)); - std::unique_ptr<gfx::GpuMemoryBuffer> buffer = CreateGpuMemoryBuffer( - gfx::Size(width, height), gfx::BufferFormat::RGBA_8888); - return CreateImage(buffer->AsClientBuffer(), width, height, internalformat); -} - void GLManager::DestroyImage(int32_t id) { gpu::gles2::ImageManager* image_manager = decoder_->GetImageManager(); DCHECK(image_manager);
diff --git a/gpu/command_buffer/tests/gl_manager.h b/gpu/command_buffer/tests/gl_manager.h index ce85a39d..b4ecb3e 100644 --- a/gpu/command_buffer/tests/gl_manager.h +++ b/gpu/command_buffer/tests/gl_manager.h
@@ -133,10 +133,6 @@ size_t height, unsigned internalformat) override; void DestroyImage(int32_t id) override; - int32_t CreateGpuMemoryBufferImage(size_t width, - size_t height, - unsigned internalformat, - unsigned usage) override; void SignalQuery(uint32_t query, const base::Closure& callback) override; void SetLock(base::Lock*) override; void EnsureWorkVisible() override;
diff --git a/gpu/config/gpu_info.cc b/gpu/config/gpu_info.cc index 6ce2d78..025cd456 100644 --- a/gpu/config/gpu_info.cc +++ b/gpu/config/gpu_info.cc
@@ -68,8 +68,6 @@ GPUInfo::GPUInfo() : optimus(false), amd_switchable(false), - lenovo_dcute(false), - adapter_luid(0), gl_reset_notification_strategy(0), software_rendering(false), direct_rendering(true), @@ -100,11 +98,8 @@ base::TimeDelta initialization_time; bool optimus; bool amd_switchable; - bool lenovo_dcute; - base::Version display_link_version; GPUDevice gpu; std::vector<GPUDevice> secondary_gpus; - uint64_t adapter_luid; std::string driver_vendor; std::string driver_version; std::string driver_date; @@ -162,12 +157,6 @@ initialization_time); enumerator->AddBool("optimus", optimus); enumerator->AddBool("amdSwitchable", amd_switchable); - enumerator->AddBool("lenovoDcute", lenovo_dcute); - if (display_link_version.IsValid()) { - enumerator->AddString("displayLinkVersion", - display_link_version.GetString()); - } - enumerator->AddInt64("adapterLuid", adapter_luid); enumerator->AddString("driverVendor", driver_vendor); enumerator->AddString("driverVersion", driver_version); enumerator->AddString("driverDate", driver_date);
diff --git a/gpu/config/gpu_info.h b/gpu/config/gpu_info.h index 86479489..a5b4f64 100644 --- a/gpu/config/gpu_info.h +++ b/gpu/config/gpu_info.h
@@ -133,26 +133,12 @@ // Computer has AMD Dynamic Switchable Graphics bool amd_switchable; - // Lenovo dCute is installed. http://crbug.com/181665. - bool lenovo_dcute; - - // Version of DisplayLink driver installed. Zero if not installed. - // http://crbug.com/177611. - base::Version display_link_version; - // Primary GPU, for exmaple, the discrete GPU in a dual GPU machine. GPUDevice gpu; // Secondary GPUs, for example, the integrated GPU in a dual GPU machine. std::vector<GPUDevice> secondary_gpus; - // On Windows, the unique identifier of the adapter the GPU process uses. - // The default is zero, which makes the browser process create its D3D device - // on the primary adapter. Note that the primary adapter can change at any - // time so it is better to specify a particular LUID. Note that valid LUIDs - // are always non-zero. - uint64_t adapter_luid; - // The vendor of the graphics driver currently installed. std::string driver_vendor;
diff --git a/gpu/config/gpu_info_collector_win.cc b/gpu/config/gpu_info_collector_win.cc index 50a54be..a12cf38 100644 --- a/gpu/config/gpu_info_collector_win.cc +++ b/gpu/config/gpu_info_collector_win.cc
@@ -33,7 +33,6 @@ #include "base/threading/thread.h" #include "base/threading/worker_pool.h" #include "base/trace_event/trace_event.h" -#include "base/win/registry.h" #include "base/win/scoped_com_initializer.h" #include "base/win/scoped_comptr.h" #include "base/win/windows_version.h" @@ -45,51 +44,6 @@ namespace { -// This must be kept in sync with histograms.xml. -enum DisplayLinkInstallationStatus { - DISPLAY_LINK_NOT_INSTALLED, - DISPLAY_LINK_7_1_OR_EARLIER, - DISPLAY_LINK_7_2_OR_LATER, - DISPLAY_LINK_INSTALLATION_STATUS_MAX -}; - -// Returns the display link driver version or an invalid version if it is -// not installed. -base::Version DisplayLinkVersion() { - base::win::RegKey key; - - if (key.Open(HKEY_LOCAL_MACHINE, L"SOFTWARE", KEY_READ | KEY_WOW64_64KEY)) - return base::Version(); - - if (key.OpenKey(L"DisplayLink", KEY_READ | KEY_WOW64_64KEY)) - return base::Version(); - - if (key.OpenKey(L"Core", KEY_READ | KEY_WOW64_64KEY)) - return base::Version(); - - base::string16 version; - if (key.ReadValue(L"Version", &version)) - return base::Version(); - - return base::Version(base::UTF16ToASCII(version)); -} - -// Returns whether Lenovo dCute is installed. -bool IsLenovoDCuteInstalled() { - base::win::RegKey key; - - if (key.Open(HKEY_LOCAL_MACHINE, L"SOFTWARE", KEY_READ | KEY_WOW64_64KEY)) - return false; - - if (key.OpenKey(L"Lenovo", KEY_READ | KEY_WOW64_64KEY)) - return false; - - if (key.OpenKey(L"Lenovo dCute", KEY_READ | KEY_WOW64_64KEY)) - return false; - - return true; -} - void DeviceIDToVendorAndDevice(const std::wstring& id, uint32_t* vendor_id, uint32_t* device_id) { @@ -318,7 +272,6 @@ int vertex_shader_minor_version = 0; int pixel_shader_major_version = 0; int pixel_shader_minor_version = 0; - gpu_info->adapter_luid = 0; if (RE2::FullMatch(gpu_info->gl_renderer, "ANGLE \\(.*\\)") && RE2::PartialMatch(gpu_info->gl_renderer, @@ -341,15 +294,6 @@ pixel_shader_major_version, pixel_shader_minor_version); - // ANGLE's EGL vendor strings are of the form: - // Google, Inc. (adapter LUID: 0123456789ABCDEF) - // The LUID is optional and identifies the GPU adapter ANGLE is using. - const char* egl_vendor = - eglQueryString(gl::GLSurfaceEGL::GetHardwareDisplay(), EGL_VENDOR); - RE2::PartialMatch(egl_vendor, - " \\(adapter LUID: ([0-9A-Fa-f]{16})\\)", - RE2::Hex(&gpu_info->adapter_luid)); - // DirectX diagnostics are collected asynchronously because it takes a // couple of seconds. } else { @@ -393,24 +337,6 @@ HMODULE nvd3d9wrap = GetModuleHandleW(L"nvd3d9wrap.dll"); gpu_info->optimus = nvd3d9wrap != NULL; - gpu_info->lenovo_dcute = IsLenovoDCuteInstalled(); - - gpu_info->display_link_version = DisplayLinkVersion(); - - if (!gpu_info->display_link_version .IsValid()) { - UMA_HISTOGRAM_ENUMERATION("GPU.DisplayLinkInstallationStatus", - DISPLAY_LINK_NOT_INSTALLED, - DISPLAY_LINK_INSTALLATION_STATUS_MAX); - } else if (gpu_info->display_link_version < base::Version("7.2")) { - UMA_HISTOGRAM_ENUMERATION("GPU.DisplayLinkInstallationStatus", - DISPLAY_LINK_7_1_OR_EARLIER, - DISPLAY_LINK_INSTALLATION_STATUS_MAX); - } else { - UMA_HISTOGRAM_ENUMERATION("GPU.DisplayLinkInstallationStatus", - DISPLAY_LINK_7_2_OR_LATER, - DISPLAY_LINK_INSTALLATION_STATUS_MAX); - } - // Taken from http://www.nvidia.com/object/device_ids.html DISPLAY_DEVICE dd; dd.cb = sizeof(DISPLAY_DEVICE);
diff --git a/gpu/gles2_conform_support/egl/context.cc b/gpu/gles2_conform_support/egl/context.cc index 041eac6..b156dda 100644 --- a/gpu/gles2_conform_support/egl/context.cc +++ b/gpu/gles2_conform_support/egl/context.cc
@@ -173,14 +173,6 @@ NOTIMPLEMENTED(); } -int32_t Context::CreateGpuMemoryBufferImage(size_t width, - size_t height, - unsigned internalformat, - unsigned usage) { - NOTIMPLEMENTED(); - return -1; -} - void Context::SignalQuery(uint32_t query, const base::Closure& callback) { NOTIMPLEMENTED(); }
diff --git a/gpu/gles2_conform_support/egl/context.h b/gpu/gles2_conform_support/egl/context.h index 7d45ea7..cff59766 100644 --- a/gpu/gles2_conform_support/egl/context.h +++ b/gpu/gles2_conform_support/egl/context.h
@@ -63,10 +63,6 @@ size_t height, unsigned internalformat) override; void DestroyImage(int32_t id) override; - int32_t CreateGpuMemoryBufferImage(size_t width, - size_t height, - unsigned internalformat, - unsigned usage) override; void SignalQuery(uint32_t query, const base::Closure& callback) override; void SetLock(base::Lock*) override; void EnsureWorkVisible() override;
diff --git a/gpu/ipc/client/command_buffer_proxy_impl.cc b/gpu/ipc/client/command_buffer_proxy_impl.cc index 552f23b..033507e 100644 --- a/gpu/ipc/client/command_buffer_proxy_impl.cc +++ b/gpu/ipc/client/command_buffer_proxy_impl.cc
@@ -545,25 +545,6 @@ Send(new GpuCommandBufferMsg_DestroyImage(route_id_, id)); } -int32_t CommandBufferProxyImpl::CreateGpuMemoryBufferImage( - size_t width, - size_t height, - unsigned internal_format, - unsigned usage) { - CheckLock(); - std::unique_ptr<gfx::GpuMemoryBuffer> buffer( - channel_->gpu_memory_buffer_manager()->CreateGpuMemoryBuffer( - gfx::Size(width, height), - gpu::DefaultBufferFormatForImageFormat(internal_format), - gfx::BufferUsage::SCANOUT, gpu::kNullSurfaceHandle)); - if (!buffer) - return -1; - - int32_t result = - CreateImage(buffer->AsClientBuffer(), width, height, internal_format); - return result; -} - uint32_t CommandBufferProxyImpl::CreateStreamTexture(uint32_t texture_id) { CheckLock(); base::AutoLock lock(last_state_lock_);
diff --git a/gpu/ipc/client/command_buffer_proxy_impl.h b/gpu/ipc/client/command_buffer_proxy_impl.h index ea8f8bfc..5a7199b4 100644 --- a/gpu/ipc/client/command_buffer_proxy_impl.h +++ b/gpu/ipc/client/command_buffer_proxy_impl.h
@@ -112,10 +112,6 @@ size_t height, unsigned internal_format) override; void DestroyImage(int32_t id) override; - int32_t CreateGpuMemoryBufferImage(size_t width, - size_t height, - unsigned internal_format, - unsigned usage) override; void SignalQuery(uint32_t query, const base::Closure& callback) override; void SetLock(base::Lock* lock) override; void EnsureWorkVisible() override;
diff --git a/gpu/ipc/common/gpu_info.mojom b/gpu/ipc/common/gpu_info.mojom index ef65b57..aa45165 100644 --- a/gpu/ipc/common/gpu_info.mojom +++ b/gpu/ipc/common/gpu_info.mojom
@@ -78,11 +78,8 @@ mojo.common.mojom.TimeDelta initialization_time; bool optimus; bool amd_switchable; - bool lenovo_dcute; - mojo.common.mojom.Version? display_link_version; GpuDevice gpu; array<GpuDevice> secondary_gpus; - uint64 adapter_luid; string driver_vendor; string driver_version; string driver_date;
diff --git a/gpu/ipc/common/gpu_info_struct_traits.cc b/gpu/ipc/common/gpu_info_struct_traits.cc index b132575c9..65857002 100644 --- a/gpu/ipc/common/gpu_info_struct_traits.cc +++ b/gpu/ipc/common/gpu_info_struct_traits.cc
@@ -219,8 +219,6 @@ gpu::GPUInfo* out) { out->optimus = data.optimus(); out->amd_switchable = data.amd_switchable(); - out->lenovo_dcute = data.lenovo_dcute(); - out->adapter_luid = data.adapter_luid(); out->gl_reset_notification_strategy = data.gl_reset_notification_strategy(); out->software_rendering = data.software_rendering(); out->direct_rendering = data.direct_rendering(); @@ -237,7 +235,6 @@ #endif return data.ReadInitializationTime(&out->initialization_time) && - data.ReadDisplayLinkVersion(&out->display_link_version) && data.ReadGpu(&out->gpu) && data.ReadSecondaryGpus(&out->secondary_gpus) && data.ReadDriverVendor(&out->driver_vendor) &&
diff --git a/gpu/ipc/common/gpu_info_struct_traits.h b/gpu/ipc/common/gpu_info_struct_traits.h index a6b9527..073ce7b 100644 --- a/gpu/ipc/common/gpu_info_struct_traits.h +++ b/gpu/ipc/common/gpu_info_struct_traits.h
@@ -145,14 +145,6 @@ return input.amd_switchable; } - static bool lenovo_dcute(const gpu::GPUInfo& input) { - return input.lenovo_dcute; - } - - static const base::Version& display_link_version(const gpu::GPUInfo& input) { - return input.display_link_version; - } - static const gpu::GPUInfo::GPUDevice& gpu(const gpu::GPUInfo& input) { return input.gpu; } @@ -162,10 +154,6 @@ return input.secondary_gpus; } - static uint64_t adapter_luid(const gpu::GPUInfo& input) { - return input.adapter_luid; - } - static const std::string& driver_vendor(const gpu::GPUInfo& input) { return input.driver_vendor; }
diff --git a/gpu/ipc/common/gpu_param_traits_macros.h b/gpu/ipc/common/gpu_param_traits_macros.h index 64248121..90120eb 100644 --- a/gpu/ipc/common/gpu_param_traits_macros.h +++ b/gpu/ipc/common/gpu_param_traits_macros.h
@@ -66,10 +66,8 @@ IPC_STRUCT_TRAITS_MEMBER(initialization_time) IPC_STRUCT_TRAITS_MEMBER(optimus) IPC_STRUCT_TRAITS_MEMBER(amd_switchable) - IPC_STRUCT_TRAITS_MEMBER(lenovo_dcute) IPC_STRUCT_TRAITS_MEMBER(gpu) IPC_STRUCT_TRAITS_MEMBER(secondary_gpus) - IPC_STRUCT_TRAITS_MEMBER(adapter_luid) IPC_STRUCT_TRAITS_MEMBER(driver_vendor) IPC_STRUCT_TRAITS_MEMBER(driver_version) IPC_STRUCT_TRAITS_MEMBER(driver_date)
diff --git a/gpu/ipc/common/struct_traits_unittest.cc b/gpu/ipc/common/struct_traits_unittest.cc index 2223921..cdd7dc00 100644 --- a/gpu/ipc/common/struct_traits_unittest.cc +++ b/gpu/ipc/common/struct_traits_unittest.cc
@@ -127,11 +127,8 @@ const base::TimeDelta initialization_time = base::TimeDelta::Max(); const bool optimus = true; const bool amd_switchable = true; - const bool lenovo_dcute = true; - const base::Version display_link_version("1.2.3.4"); const gpu::GPUInfo::GPUDevice gpu; const std::vector<gpu::GPUInfo::GPUDevice> secondary_gpus; - const uint64_t adapter_luid = 0x10de; const std::string driver_vendor = "driver_vendor"; const std::string driver_version = "driver_version"; const std::string driver_date = "driver_date"; @@ -177,11 +174,8 @@ input.initialization_time = initialization_time; input.optimus = optimus; input.amd_switchable = amd_switchable; - input.lenovo_dcute = lenovo_dcute; - input.display_link_version = display_link_version; input.gpu = gpu; input.secondary_gpus = secondary_gpus; - input.adapter_luid = adapter_luid; input.driver_vendor = driver_vendor; input.driver_version = driver_version; input.driver_date = driver_date; @@ -226,8 +220,6 @@ EXPECT_EQ(optimus, output.optimus); EXPECT_EQ(amd_switchable, output.amd_switchable); - EXPECT_EQ(lenovo_dcute, output.lenovo_dcute); - EXPECT_TRUE(display_link_version.CompareTo(output.display_link_version) == 0); EXPECT_EQ(gpu.vendor_id, output.gpu.vendor_id); EXPECT_EQ(gpu.device_id, output.gpu.device_id); EXPECT_EQ(gpu.active, output.gpu.active); @@ -243,7 +235,6 @@ EXPECT_EQ(expected_gpu.vendor_string, actual_gpu.vendor_string); EXPECT_EQ(expected_gpu.device_string, actual_gpu.device_string); } - EXPECT_EQ(adapter_luid, output.adapter_luid); EXPECT_EQ(driver_vendor, output.driver_vendor); EXPECT_EQ(driver_version, output.driver_version); EXPECT_EQ(driver_date, output.driver_date); @@ -303,7 +294,6 @@ mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy(); gpu::GPUInfo output; proxy->EchoGpuInfo(input, &output); - EXPECT_FALSE(output.display_link_version.IsValid()); } TEST_F(StructTraitsTest, Mailbox) {
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc index 85580ce7..cfdc879 100644 --- a/gpu/ipc/in_process_command_buffer.cc +++ b/gpu/ipc/in_process_command_buffer.cc
@@ -828,26 +828,6 @@ image_manager->RemoveImage(id); } -int32_t InProcessCommandBuffer::CreateGpuMemoryBufferImage( - size_t width, - size_t height, - unsigned internalformat, - unsigned usage) { - CheckSequencedThread(); - - DCHECK(gpu_memory_buffer_manager_); - std::unique_ptr<gfx::GpuMemoryBuffer> buffer( - gpu_memory_buffer_manager_->CreateGpuMemoryBuffer( - gfx::Size(base::checked_cast<int>(width), - base::checked_cast<int>(height)), - gpu::DefaultBufferFormatForImageFormat(internalformat), - gfx::BufferUsage::SCANOUT, gpu::kNullSurfaceHandle)); - if (!buffer) - return -1; - - return CreateImage(buffer->AsClientBuffer(), width, height, internalformat); -} - void InProcessCommandBuffer::FenceSyncReleaseOnGpuThread(uint64_t release) { DCHECK(!sync_point_client_->client_state()->IsFenceSyncReleased(release)); gles2::MailboxManager* mailbox_manager = @@ -1048,7 +1028,7 @@ void InProcessCommandBuffer::DidCreateAcceleratedSurfaceChildWindow( SurfaceHandle parent_window, SurfaceHandle child_window) { - // TODO(fsamuel): Implement this. + ::SetParent(child_window, parent_window); } #endif
diff --git a/gpu/ipc/in_process_command_buffer.h b/gpu/ipc/in_process_command_buffer.h index 6a55ec0..5ed122b 100644 --- a/gpu/ipc/in_process_command_buffer.h +++ b/gpu/ipc/in_process_command_buffer.h
@@ -115,10 +115,6 @@ size_t height, unsigned internalformat) override; void DestroyImage(int32_t id) override; - int32_t CreateGpuMemoryBufferImage(size_t width, - size_t height, - unsigned internalformat, - unsigned usage) override; void SignalQuery(uint32_t query_id, const base::Closure& callback) override; void SetLock(base::Lock*) override; void EnsureWorkVisible() override;
diff --git a/headless/public/util/flat_dom_tree_extractor.cc b/headless/public/util/flat_dom_tree_extractor.cc index 97aaeed8e..1ac9210 100644 --- a/headless/public/util/flat_dom_tree_extractor.cc +++ b/headless/public/util/flat_dom_tree_extractor.cc
@@ -26,6 +26,7 @@ callback_ = std::move(callback); + devtools_client_->GetDOM()->Enable(); devtools_client_->GetDOM()->GetFlattenedDocument( dom::GetFlattenedDocumentParams::Builder() .SetDepth(-1) @@ -62,6 +63,7 @@ } ExtractLayoutTreeNodes(); ExtractComputedStyles(); + devtools_client_->GetDOM()->Disable(); work_in_progress_ = false;
diff --git a/headless/public/util/flat_dom_tree_extractor_browsertest.cc b/headless/public/util/flat_dom_tree_extractor_browsertest.cc index dcb418d..e897301 100644 --- a/headless/public/util/flat_dom_tree_extractor_browsertest.cc +++ b/headless/public/util/flat_dom_tree_extractor_browsertest.cc
@@ -55,7 +55,6 @@ extractor_.reset(new FlatDomTreeExtractor(devtools_client_.get())); - devtools_client_->GetDOM()->Enable(); std::vector<std::string> css_whitelist = { "color", "display", "font-style", "font-family", "margin-left", "margin-right", "margin-top", "margin-bottom"}; @@ -911,7 +910,6 @@ << i; } - devtools_client_->GetDOM()->Disable(); FinishAsynchronousTest(); }
diff --git a/ios/build/bots/chromium.mac/ios-simulator-eg.json b/ios/build/bots/chromium.mac/ios-simulator-eg.json new file mode 100644 index 0000000..39b591f --- /dev/null +++ b/ios/build/bots/chromium.mac/ios-simulator-eg.json
@@ -0,0 +1,102 @@ +{ + "comments": [ + "EarlGrey Tests for 64-bit iOS 10.0 simulators." + ], + "xcode version": "8.0", + "gn_args": [ + "goma_dir=\"$(goma_dir)\"", + "is_component_build=false", + "is_debug=true", + "target_cpu=\"x64\"", + "target_os=\"ios\"", + "use_goma=true" + ], + "configuration": "Debug", + "sdk": "iphonesimulator10.0", + "tests": [ + { + "app": "ios_chrome_integration_egtests", + "device type": "iPhone 6s", + "os": "10.0", + "xctest": true + }, + { + "app": "ios_chrome_settings_egtests", + "device type": "iPhone 6s", + "os": "10.0", + "xctest": true + }, + { + "app": "ios_chrome_smoke_egtests", + "device type": "iPhone 6s", + "os": "10.0", + "xctest": true + }, + { + "app": "ios_chrome_ui_egtests", + "device type": "iPhone 6s", + "os": "10.0", + "xctest": true + }, + { + "app": "ios_chrome_web_egtests", + "device type": "iPhone 6s", + "os": "10.0", + "xctest": true + }, + { + "app": "ios_showcase_egtests", + "device type": "iPhone 6s", + "os": "10.0", + "xctest": true + }, + { + "app": "ios_web_shell_egtests", + "device type": "iPhone 6s", + "os": "10.0", + "xctest": true + }, + { + "app": "ios_chrome_integration_egtests", + "device type": "iPad Air 2", + "os": "10.0", + "xctest": true + }, + { + "app": "ios_chrome_settings_egtests", + "device type": "iPad Air 2", + "os": "10.0", + "xctest": true + }, + { + "app": "ios_chrome_smoke_egtests", + "device type": "iPad Air 2", + "os": "10.0", + "xctest": true + }, + { + "app": "ios_chrome_ui_egtests", + "device type": "iPad Air 2", + "os": "10.0", + "xctest": true + }, + { + "app": "ios_chrome_web_egtests", + "device type": "iPad Air 2", + "os": "10.0", + "xctest": true + }, + { + "app": "ios_showcase_egtests", + "device type": "iPad Air 2", + "os": "10.0", + "xctest": true + }, + { + "app": "ios_web_shell_egtests", + "device type": "iPad Air 2", + "os": "10.0", + "xctest": true + } + ] +}
diff --git a/ios/chrome/browser/tabs/tab_model.mm b/ios/chrome/browser/tabs/tab_model.mm index 7cd840e..94ee048 100644 --- a/ios/chrome/browser/tabs/tab_model.mm +++ b/ios/chrome/browser/tabs/tab_model.mm
@@ -157,6 +157,7 @@ openedByDOM:(BOOL)openedByDOM atIndex:(NSUInteger)index inBackground:(BOOL)inBackground; + // Call to switch the selected tab. Broadcasts about the change in selection. // It's ok for |newTab| to be nil in case the last tab is going away. In that // case, the "tab deselected" notification gets sent, but no corresponding @@ -165,11 +166,20 @@ - (void)changeSelectedTabFrom:(Tab*)oldTab to:(Tab*)newTab persistState:(BOOL)persist; + // Tells the snapshot cache the adjacent tab session ids. - (void)updateSnapshotCache:(Tab*)tab; + // Helper method that posts a notification with the given name with |tab| // in the userInfo dictionary under the kTabModelTabKey. - (void)postNotificationName:(NSString*)notificationName withTab:(Tab*)tab; + +// Helper method to restore a saved session and control if the state should +// be persisted or not. Used to implement the public -restoreSessionWindow: +// method and restoring session in the initialiser. +- (BOOL)restoreSessionWindow:(SessionWindowIOS*)window + persistState:(BOOL)persistState; + @end @implementation TabModel @@ -256,56 +266,35 @@ _syncedWindowDelegate.reset(new TabModelSyncedWindowDelegate(self)); _tabs.reset([[NSMutableArray alloc] init]); - NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter]; if (window) { - web::WebState::CreateParams params(_browserState); - for (CRWNavigationManagerStorage* session in window.sessions) { - std::unique_ptr<web::WebState> webState = - web::WebState::Create(params, session); - DCHECK_EQ(webState->GetBrowserState(), _browserState); - // Restore the CertificatePolicyCache. - UpdateCertificatePolicyCacheFromWebState(webState.get()); - // Create a new tab for each entry in the window. Don't send delegate - // notifications for each restored tab, only when all done. - base::scoped_nsobject<Tab> tab( - [[Tab alloc] initWithWebState:std::move(webState) model:self]); - [tab webController].usePlaceholderOverlay = YES; - [tab fetchFavicon]; - [_tabs addObject:tab]; - - TabParentingGlobalObserver::GetInstance()->OnTabParented( - tab.get().webState); - } - if ([_tabs count]) { - DCHECK(window.selectedIndex < [_tabs count]); - _currentTab.reset([self tabAtIndex:window.selectedIndex]); - DCHECK(_currentTab); - if (_tabUsageRecorder) - _tabUsageRecorder->InitialRestoredTabs(_currentTab, _tabs); - // Perform initializations for affiliated objects which update the - // session information related to the current tab. - [_currentTab updateLastVisitedTimestamp]; - [self saveSessionImmediately:NO]; - } + DCHECK([_observers empty]); + // Restore the session and reset the session metrics (as the event have + // not been generated by the user but by a cold start cycle). + [self restoreSessionWindow:window persistState:NO]; + [self resetSessionMetrics]; } _orderController.reset( [[TabModelOrderController alloc] initWithTabModel:self]); + // Register for resign active notification. - [defaultCenter addObserver:self - selector:@selector(willResignActive:) - name:UIApplicationWillResignActiveNotification - object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(willResignActive:) + name:UIApplicationWillResignActiveNotification + object:nil]; // Register for background notification. - [defaultCenter addObserver:self - selector:@selector(applicationDidEnterBackground:) - name:UIApplicationDidEnterBackgroundNotification - object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(applicationDidEnterBackground:) + name:UIApplicationDidEnterBackgroundNotification + object:nil]; // Register for foregrounding notification. - [defaultCenter addObserver:self - selector:@selector(applicationWillEnterForeground:) - name:UIApplicationWillEnterForegroundNotification - object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(applicationWillEnterForeground:) + name:UIApplicationWillEnterForegroundNotification + object:nil]; // Associate with ios::ChromeBrowserState. RegisterTabModelWithChromeBrowserState(_browserState, self); @@ -319,55 +308,7 @@ } - (BOOL)restoreSessionWindow:(SessionWindowIOS*)window { - DCHECK(_browserState); - DCHECK(window); - NSArray* sessions = window.sessions; - if (!sessions.count) - return NO; - size_t oldCount = [_tabs count]; - size_t index = oldCount; - web::WebState::CreateParams params(_browserState); - for (CRWNavigationManagerStorage* session in sessions) { - std::unique_ptr<web::WebState> webState = - web::WebState::Create(params, session); - DCHECK_EQ(webState->GetBrowserState(), _browserState); - Tab* tab = [self insertTabWithWebState:std::move(webState) atIndex:index++]; - tab.webController.usePlaceholderOverlay = YES; - // Restore the CertificatePolicyCache. Note that after calling Pass() - // |webState| is invalid, so we need to get the webstate from |tab|. - UpdateCertificatePolicyCacheFromWebState(tab.webState); - } - DCHECK([_tabs count] > oldCount); - // If any tab was restored, the saved selected tab must be selected. - if ([_tabs count] > oldCount) { - NSUInteger selectedIndex = window.selectedIndex; - if (selectedIndex == NSNotFound) - selectedIndex = oldCount; - else - selectedIndex += oldCount; - DCHECK(selectedIndex < [_tabs count]); - Tab* newTab = [self tabAtIndex:selectedIndex]; - DCHECK(newTab); - [self changeSelectedTabFrom:_currentTab to:newTab persistState:YES]; - - // If there was only one tab and it was the new tab page, clobber it. - if (oldCount == 1) { - Tab* tab = [_tabs objectAtIndex:0]; - if (tab.url == GURL(kChromeUINewTabURL)) { - [self closeTab:tab]; - if (_tabUsageRecorder) - _tabUsageRecorder->InitialRestoredTabs(_currentTab, _tabs); - return YES; - } - } - if (_tabUsageRecorder) { - _tabUsageRecorder->InitialRestoredTabs( - _currentTab, - [_tabs subarrayWithRange:NSMakeRange(oldCount, - [_tabs count] - oldCount)]); - } - } - return NO; + return [self restoreSessionWindow:window persistState:YES]; } - (void)saveSessionImmediately:(BOOL)immediately { @@ -1002,6 +943,61 @@ userInfo:userInfo]; } +- (BOOL)restoreSessionWindow:(SessionWindowIOS*)window + persistState:(BOOL)persistState { + DCHECK(_browserState); + DCHECK(window); + + NSArray* sessions = window.sessions; + if (!sessions.count) + return NO; + + size_t oldCount = [_tabs count]; + web::WebState::CreateParams params(_browserState); + + for (CRWNavigationManagerStorage* session in sessions) { + std::unique_ptr<web::WebState> webState = + web::WebState::Create(params, session); + DCHECK_EQ(webState->GetBrowserState(), _browserState); + Tab* tab = + [self insertTabWithWebState:std::move(webState) atIndex:[_tabs count]]; + tab.webController.usePlaceholderOverlay = YES; + + // Restore the CertificatePolicyCache (note that webState is invalid after + // passing it via move semantic to -insertTabWithWebState:atIndex:). + UpdateCertificatePolicyCacheFromWebState(tab.webState); + } + DCHECK_GT([_tabs count], oldCount); + + // Update the selected tab if there was a selected Tab in the saved session. + if (window.selectedIndex != NSNotFound) { + NSUInteger selectedIndex = window.selectedIndex + oldCount; + DCHECK_LT(selectedIndex, [_tabs count]); + DCHECK([self tabAtIndex:selectedIndex]); + [self changeSelectedTabFrom:_currentTab + to:[self tabAtIndex:selectedIndex] + persistState:persistState]; + } + + // If there was only one tab and it was the new tab page, clobber it. + BOOL closedNTPTab = NO; + if (oldCount == 1) { + Tab* tab = [_tabs objectAtIndex:0]; + if (tab.url == GURL(kChromeUINewTabURL)) { + [self closeTab:tab]; + closedNTPTab = YES; + oldCount = 0; + } + } + if (_tabUsageRecorder) { + _tabUsageRecorder->InitialRestoredTabs( + _currentTab, + [_tabs + subarrayWithRange:NSMakeRange(oldCount, [_tabs count] - oldCount)]); + } + return closedNTPTab; +} + #pragma mark - Notification Handlers // Called when UIApplicationWillResignActiveNotification is received.
diff --git a/ios/chrome/browser/ui/first_run/BUILD.gn b/ios/chrome/browser/ui/first_run/BUILD.gn index 064ba14..c65ec88 100644 --- a/ios/chrome/browser/ui/first_run/BUILD.gn +++ b/ios/chrome/browser/ui/first_run/BUILD.gn
@@ -23,6 +23,7 @@ } source_set("first_run") { + configs += [ "//build/config/compiler:enable_arc" ] sources = [ "first_run_chrome_signin_view_controller.h", "first_run_chrome_signin_view_controller.mm",
diff --git a/ios/chrome/browser/ui/first_run/first_run_chrome_signin_view_controller.mm b/ios/chrome/browser/ui/first_run/first_run_chrome_signin_view_controller.mm index 099d682..684311c 100644 --- a/ios/chrome/browser/ui/first_run/first_run_chrome_signin_view_controller.mm +++ b/ios/chrome/browser/ui/first_run/first_run_chrome_signin_view_controller.mm
@@ -4,7 +4,6 @@ #import "ios/chrome/browser/ui/first_run/first_run_chrome_signin_view_controller.h" -#import "base/mac/scoped_nsobject.h" #include "base/metrics/user_metrics.h" #include "components/signin/core/browser/signin_metrics.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" @@ -22,6 +21,10 @@ #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h" #import "ui/base/l10n/l10n_util.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + NSString* const kSignInButtonAccessibilityIdentifier = @"SignInButtonAccessibilityIdentifier"; NSString* const kSignInSkipButtonAccessibilityIdentifier = @@ -29,9 +32,9 @@ @interface FirstRunChromeSigninViewController ()< ChromeSigninViewControllerDelegate> { - TabModel* _tabModel; // weak - base::scoped_nsobject<FirstRunConfiguration> _firstRunConfig; - ChromeIdentity* _identity; + __weak TabModel* _tabModel; + FirstRunConfiguration* _firstRunConfig; + __weak ChromeIdentity* _identity; BOOL _hasRecordedSigninStarted; } @@ -50,7 +53,7 @@ signInIdentity:identity]; if (self) { _tabModel = tabModel; - _firstRunConfig.reset([firstRunConfig retain]); + _firstRunConfig = firstRunConfig; _identity = identity; self.delegate = self; } @@ -60,7 +63,6 @@ - (void)dealloc { self.delegate = nil; _tabModel = nil; - [super dealloc]; } - (void)viewDidLoad {
diff --git a/ios/chrome/browser/ui/first_run/first_run_util.mm b/ios/chrome/browser/ui/first_run/first_run_util.mm index 7fa7cfc..766b2a2 100644 --- a/ios/chrome/browser/ui/first_run/first_run_util.mm +++ b/ios/chrome/browser/ui/first_run/first_run_util.mm
@@ -24,6 +24,10 @@ #include "ios/web/public/web_thread.h" #import "ui/gfx/ios/NSString+CrStringDrawing.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + NSString* const kChromeFirstRunUIWillFinishNotification = @"kChromeFirstRunUIWillFinishNotification"; @@ -66,7 +70,7 @@ count++; *stop = count == index; }]; - NSMutableString* textWithNewline = [[text mutableCopy] autorelease]; + NSMutableString* textWithNewline = [text mutableCopy]; [textWithNewline insertString:@"\n" atIndex:range.location]; return textWithNewline; }
diff --git a/ios/chrome/browser/ui/first_run/static_file_view_controller.mm b/ios/chrome/browser/ui/first_run/static_file_view_controller.mm index 228901cd..369929a4 100644 --- a/ios/chrome/browser/ui/first_run/static_file_view_controller.mm +++ b/ios/chrome/browser/ui/first_run/static_file_view_controller.mm
@@ -7,7 +7,6 @@ #import <WebKit/WebKit.h> #include "base/logging.h" -#include "base/mac/scoped_nsobject.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/ui/material_components/utils.h" #include "ios/chrome/browser/ui/rtl_geometry.h" @@ -16,15 +15,19 @@ #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h" #import "ios/web/public/web_view_creation_util.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + @interface StaticFileViewController ()<UIScrollViewDelegate> { ios::ChromeBrowserState* _browserState; // weak - base::scoped_nsobject<NSURL> _URL; + NSURL* _URL; // YES if the header has been configured for RTL. BOOL _headerLaidOutForRTL; // The web view used to display the static content. - base::scoped_nsobject<WKWebView> _webView; + WKWebView* _webView; // The header. - base::scoped_nsobject<MDCAppBar> _appBar; + MDCAppBar* _appBar; } @end @@ -37,17 +40,16 @@ DCHECK(URL); self = [super init]; if (self) { - _appBar.reset([[MDCAppBar alloc] init]); + _appBar = [[MDCAppBar alloc] init]; [self addChildViewController:[_appBar headerViewController]]; _browserState = browserState; - _URL.reset([URL retain]); + _URL = URL; } return self; } - (void)dealloc { [_webView scrollView].delegate = nil; - [super dealloc]; } #pragma mark - UIViewController @@ -55,7 +57,7 @@ - (void)viewDidLoad { [super viewDidLoad]; - _webView.reset([web::BuildWKWebView(self.view.bounds, _browserState) retain]); + _webView = web::BuildWKWebView(self.view.bounds, _browserState); [_webView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
diff --git a/ios/chrome/browser/ui/first_run/welcome_to_chrome_view.h b/ios/chrome/browser/ui/first_run/welcome_to_chrome_view.h index 9fcbd6c..a819590d 100644 --- a/ios/chrome/browser/ui/first_run/welcome_to_chrome_view.h +++ b/ios/chrome/browser/ui/first_run/welcome_to_chrome_view.h
@@ -23,7 +23,7 @@ // The first view shown to the user after fresh installs. @interface WelcomeToChromeView : UIView -@property(nonatomic, assign) id<WelcomeToChromeViewDelegate> delegate; +@property(nonatomic, weak) id<WelcomeToChromeViewDelegate> delegate; // Whether the stats reporting check box is selected. @property(nonatomic, assign, getter=isCheckBoxSelected) BOOL checkBoxSelected;
diff --git a/ios/chrome/browser/ui/first_run/welcome_to_chrome_view.mm b/ios/chrome/browser/ui/first_run/welcome_to_chrome_view.mm index 8cad5b67..e5727625 100644 --- a/ios/chrome/browser/ui/first_run/welcome_to_chrome_view.mm +++ b/ios/chrome/browser/ui/first_run/welcome_to_chrome_view.mm
@@ -5,9 +5,7 @@ #import "ios/chrome/browser/ui/first_run/welcome_to_chrome_view.h" #include "base/i18n/rtl.h" -#import "base/ios/weak_nsobject.h" #include "base/logging.h" -#import "base/mac/scoped_nsobject.h" #include "base/strings/sys_string_conversions.h" #import "ios/chrome/browser/ui/UIView+SizeClassSupport.h" #include "ios/chrome/browser/ui/fancy_ui/primary_action_button.h" @@ -23,6 +21,10 @@ #include "ui/base/l10n/l10n_util.h" #include "url/gurl.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace { // Accessibility identifier for the checkbox button. @@ -70,34 +72,32 @@ } // namespace @interface WelcomeToChromeView () { - // Backing objects for properties of the same name. - base::WeakNSProtocol<id<WelcomeToChromeViewDelegate>> _delegate; - base::scoped_nsobject<UIView> _containerView; - base::scoped_nsobject<UILabel> _titleLabel; - base::scoped_nsobject<UIImageView> _imageView; - base::scoped_nsobject<UILabel> _TOSLabel; - base::scoped_nsobject<LabelLinkController> _TOSLabelLinkController; - base::scoped_nsobject<UIButton> _checkBoxButton; - base::scoped_nsobject<UILabel> _optInLabel; - base::scoped_nsobject<PrimaryActionButton> _OKButton; + UIView* _containerView; + UILabel* _titleLabel; + UIImageView* _imageView; + UILabel* _TOSLabel; + LabelLinkController* _TOSLabelLinkController; + UIButton* _checkBoxButton; + UILabel* _optInLabel; + PrimaryActionButton* _OKButton; } // Subview properties are lazily instantiated upon their first use. // A container view used to layout and center subviews. -@property(nonatomic, readonly) UIView* containerView; +@property(strong, nonatomic, readonly) UIView* containerView; // The "Welcome to Chrome" label that appears at the top of the view. -@property(nonatomic, readonly) UILabel* titleLabel; +@property(strong, nonatomic, readonly) UILabel* titleLabel; // The Chrome logo image view. -@property(nonatomic, readonly) UIImageView* imageView; +@property(strong, nonatomic, readonly) UIImageView* imageView; // The "Terms of Service" label. -@property(nonatomic, readonly) UILabel* TOSLabel; +@property(strong, nonatomic, readonly) UILabel* TOSLabel; // The stats reporting opt-in label. -@property(nonatomic, readonly) UILabel* optInLabel; +@property(strong, nonatomic, readonly) UILabel* optInLabel; // The stats reporting opt-in checkbox button. -@property(nonatomic, readonly) UIButton* checkBoxButton; +@property(strong, nonatomic, readonly) UIButton* checkBoxButton; // The "Accept & Continue" button. -@property(nonatomic, readonly) PrimaryActionButton* OKButton; +@property(strong, nonatomic, readonly) PrimaryActionButton* OKButton; // Subview layout methods. They must be called in the order declared here, as // subsequent subview layouts depend on the layouts that precede them. @@ -134,6 +134,8 @@ @implementation WelcomeToChromeView +@synthesize delegate = _delegate; + - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { @@ -162,7 +164,7 @@ self.imageView.center = CGPointMake(CGRectGetMidX(self.containerView.bounds), CGRectGetMidY(self.containerView.bounds)); - base::WeakNSObject<WelcomeToChromeView> weakSelf(self); + __weak WelcomeToChromeView* weakSelf = self; [UIView animateWithDuration:kAnimationDuration delay:kAnimationDelay options:UIViewAnimationCurveEaseInOut @@ -179,14 +181,6 @@ #pragma mark - Accessors -- (id<WelcomeToChromeViewDelegate>)delegate { - return _delegate; -} - -- (void)setDelegate:(id<WelcomeToChromeViewDelegate>)delegate { - _delegate.reset(delegate); -} - - (BOOL)isCheckBoxSelected { return self.checkBoxButton.selected; } @@ -198,15 +192,15 @@ - (UIView*)containerView { if (!_containerView) { - _containerView.reset([[UIView alloc] initWithFrame:CGRectZero]); + _containerView = [[UIView alloc] initWithFrame:CGRectZero]; [_containerView setBackgroundColor:[UIColor whiteColor]]; } - return _containerView.get(); + return _containerView; } - (UILabel*)titleLabel { if (!_titleLabel) { - _titleLabel.reset([[UILabel alloc] initWithFrame:CGRectZero]); + _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; [_titleLabel setBackgroundColor:[UIColor whiteColor]]; [_titleLabel setNumberOfLines:0]; [_titleLabel setLineBreakMode:NSLineBreakByWordWrapping]; @@ -214,41 +208,41 @@ [_titleLabel setText:l10n_util::GetNSString(IDS_IOS_FIRSTRUN_WELCOME_TO_CHROME)]; } - return _titleLabel.get(); + return _titleLabel; } - (UIImageView*)imageView { if (!_imageView) { UIImage* image = [UIImage imageNamed:kAppLogoImageName]; - _imageView.reset([[UIImageView alloc] initWithImage:image]); + _imageView = [[UIImageView alloc] initWithImage:image]; [_imageView setBackgroundColor:[UIColor whiteColor]]; } - return _imageView.get(); + return _imageView; } - (UILabel*)TOSLabel { if (!_TOSLabel) { - _TOSLabel.reset([[UILabel alloc] initWithFrame:CGRectZero]); + _TOSLabel = [[UILabel alloc] initWithFrame:CGRectZero]; [_TOSLabel setNumberOfLines:0]; [_TOSLabel setTextAlignment:NSTextAlignmentCenter]; } - return _TOSLabel.get(); + return _TOSLabel; } - (UILabel*)optInLabel { if (!_optInLabel) { - _optInLabel.reset([[UILabel alloc] initWithFrame:CGRectZero]); + _optInLabel = [[UILabel alloc] initWithFrame:CGRectZero]; [_optInLabel setNumberOfLines:0]; [_optInLabel setText:l10n_util::GetNSString(IDS_IOS_FIRSTRUN_NEW_OPT_IN_LABEL)]; [_optInLabel setTextAlignment:NSTextAlignmentNatural]; } - return _optInLabel.get(); + return _optInLabel; } - (UIButton*)checkBoxButton { if (!_checkBoxButton) { - _checkBoxButton.reset([[UIButton alloc] initWithFrame:CGRectZero]); + _checkBoxButton = [[UIButton alloc] initWithFrame:CGRectZero]; [_checkBoxButton setBackgroundColor:[UIColor clearColor]]; [_checkBoxButton addTarget:self action:@selector(checkBoxButtonWasTapped) @@ -263,12 +257,12 @@ [_checkBoxButton setImage:[UIImage imageNamed:kCheckBoxCheckedImageName] forState:UIControlStateSelected]; } - return _checkBoxButton.get(); + return _checkBoxButton; } - (PrimaryActionButton*)OKButton { if (!_OKButton) { - _OKButton.reset([[PrimaryActionButton alloc] initWithFrame:CGRectZero]); + _OKButton = [[PrimaryActionButton alloc] initWithFrame:CGRectZero]; [_OKButton addTarget:self action:@selector(OKButtonWasTapped) forControlEvents:UIControlEventTouchUpInside]; @@ -281,7 +275,7 @@ SetA11yLabelAndUiAutomationName( _OKButton, IDS_IOS_FIRSTRUN_OPT_IN_ACCEPT_BUTTON, @"Accept & Continue"); } - return _OKButton.get(); + return _OKButton; } #pragma mark - Layout @@ -359,16 +353,16 @@ linkTextRange.length++; } - base::WeakNSObject<WelcomeToChromeView> weakSelf(self); + __weak WelcomeToChromeView* weakSelf = self; ProceduralBlockWithURL action = ^(const GURL& url) { - base::scoped_nsobject<WelcomeToChromeView> strongSelf([weakSelf retain]); + WelcomeToChromeView* strongSelf = weakSelf; if (!strongSelf) return; [[strongSelf delegate] welcomeToChromeViewDidTapTOSLink:strongSelf]; }; - _TOSLabelLinkController.reset( - [[LabelLinkController alloc] initWithLabel:_TOSLabel action:action]); + _TOSLabelLinkController = + [[LabelLinkController alloc] initWithLabel:_TOSLabel action:action]; [_TOSLabelLinkController addLinkWithRange:linkTextRange url:GURL("internal://terms-of-service")];
diff --git a/ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.mm b/ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.mm index 445438c6..ef930b3 100644 --- a/ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.mm +++ b/ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.mm
@@ -5,12 +5,10 @@ #include "ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.h" #include "base/i18n/rtl.h" -#include "base/ios/weak_nsobject.h" #include "base/logging.h" #include "base/mac/bundle_locations.h" #include "base/mac/foundation_util.h" -#include "base/mac/objc_property_releaser.h" -#include "base/mac/scoped_nsobject.h" + #include "base/strings/sys_string_conversions.h" #include "components/metrics/metrics_pref_names.h" #include "components/metrics/metrics_reporting_default_state.h" @@ -33,6 +31,10 @@ #import "ios/public/provider/chrome/browser/signin/chrome_identity_service.h" #include "ui/base/l10n/l10n_util.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + NSString* const kUMAMetricsButtonAccessibilityIdentifier = @"UMAMetricsButtonAccessibilityIdentifier"; @@ -47,9 +49,7 @@ @interface WelcomeToChromeViewController ()<WelcomeToChromeViewDelegate> { ios::ChromeBrowserState* browserState_; // weak - TabModel* tabModel_; // weak - base::mac::ObjCPropertyReleaser - propertyReleaser_WelcomeToChromeViewController_; + __weak TabModel* tabModel_; } // The animation which occurs at launch has run. @@ -81,8 +81,6 @@ if (self) { browserState_ = browserState; tabModel_ = tabModel; - propertyReleaser_WelcomeToChromeViewController_.Init( - self, [WelcomeToChromeViewController class]); } return self; } @@ -99,8 +97,8 @@ } - (void)loadView { - base::scoped_nsobject<WelcomeToChromeView> welcomeToChromeView( - [[WelcomeToChromeView alloc] initWithFrame:CGRectZero]); + WelcomeToChromeView* welcomeToChromeView = + [[WelcomeToChromeView alloc] initWithFrame:CGRectZero]; [welcomeToChromeView setDelegate:self]; [welcomeToChromeView setCheckBoxSelected:[[self class] defaultStatsCheckboxValue]]; @@ -130,19 +128,18 @@ std::string tos = GetTermsOfServicePath(); NSString* path = [[base::mac::FrameworkBundle() bundlePath] stringByAppendingPathComponent:base::SysUTF8ToNSString(tos)]; - base::scoped_nsobject<NSURLComponents> components( - [[NSURLComponents alloc] init]); + NSURLComponents* components = [[NSURLComponents alloc] init]; [components setScheme:@"file"]; [components setHost:@""]; [components setPath:path]; - return [[components URL] retain]; + return [components URL]; } // Displays the file at the given URL in a StaticFileViewController. - (void)openStaticFileWithURL:(NSURL*)url title:(NSString*)title { - base::scoped_nsobject<StaticFileViewController> staticViewController( + StaticFileViewController* staticViewController = [[StaticFileViewController alloc] initWithBrowserState:browserState_ - URL:url]); + URL:url]; [staticViewController setTitle:title]; [self.navigationController pushViewController:staticViewController animated:YES]; @@ -152,7 +149,7 @@ - (void)welcomeToChromeViewDidTapTOSLink:(WelcomeToChromeView*)view { NSString* title = l10n_util::GetNSString(IDS_IOS_FIRSTRUN_TERMS_TITLE); - base::scoped_nsobject<NSURL> tosUrl([self newTermsOfServiceUrl]); + NSURL* tosUrl = [self newTermsOfServiceUrl]; [self openStaticFileWithURL:tosUrl title:title]; } @@ -160,18 +157,17 @@ GetApplicationContext()->GetLocalState()->SetBoolean( metrics::prefs::kMetricsReportingEnabled, view.checkBoxSelected); - base::scoped_nsobject<FirstRunConfiguration> firstRunConfig( - [[FirstRunConfiguration alloc] init]); + FirstRunConfiguration* firstRunConfig = [[FirstRunConfiguration alloc] init]; bool hasSSOAccounts = ios::GetChromeBrowserProvider() ->GetChromeIdentityService() ->HasIdentities(); [firstRunConfig setHasSSOAccount:hasSSOAccounts]; - base::scoped_nsobject<FirstRunChromeSigninViewController> signInController( + FirstRunChromeSigninViewController* signInController = [[FirstRunChromeSigninViewController alloc] initWithBrowserState:browserState_ tabModel:tabModel_ firstRunConfig:firstRunConfig - signInIdentity:nil]); + signInIdentity:nil]; CATransition* transition = [CATransition animation]; transition.duration = kFadeOutAnimationDuration;
diff --git a/ios/chrome/browser/ui/history/history_ui_egtest.mm b/ios/chrome/browser/ui/history/history_ui_egtest.mm index feb43e4b..df453b4f 100644 --- a/ios/chrome/browser/ui/history/history_ui_egtest.mm +++ b/ios/chrome/browser/ui/history/history_ui_egtest.mm
@@ -6,6 +6,7 @@ #import <UIKit/UIKit.h> #import <XCTest/XCTest.h> +#include "base/strings/stringprintf.h" #include "base/strings/sys_string_conversions.h" #include "components/browsing_data/core/pref_names.h" #include "components/prefs/pref_service.h" @@ -41,19 +42,40 @@ #endif using chrome_test_util::ButtonWithAccessibilityLabelId; +using chrome_test_util::WebViewContainingText; namespace { char kURL1[] = "http://firstURL"; char kURL2[] = "http://secondURL"; char kURL3[] = "http://thirdURL"; -char kResponse1[] = "Test Page 1"; -char kResponse2[] = "Test Page 2"; -char kResponse3[] = "Test Page 3"; +char kTitle1[] = "Page 1"; +char kTitle2[] = "Page 2"; +char kResponse1[] = "Test Page 1 content"; +char kResponse2[] = "Test Page 2 content"; +char kResponse3[] = "Test Page 3 content"; -// Matcher for entry in history for URL. -id<GREYMatcher> HistoryEntryWithUrl(const GURL& url) { - NSString* url_spec = base::SysUTF8ToNSString(url.spec()); - return grey_allOf(grey_text(url_spec), grey_sufficientlyVisible(), nil); +// Matcher for entry in history for URL and title. +id<GREYMatcher> HistoryEntry(const GURL& url, const std::string& title) { + NSString* url_spec_text = base::SysUTF8ToNSString(url.spec()); + NSString* title_text = base::SysUTF8ToNSString(title); + + MatchesBlock matches = ^BOOL(HistoryEntryCell* cell) { + return [cell.textLabel.text isEqual:title_text] && + [cell.detailTextLabel.text isEqual:url_spec_text]; + }; + + DescribeToBlock describe = ^(id<GREYDescription> description) { + [description appendText:@"view containing URL text: "]; + [description appendText:url_spec_text]; + [description appendText:@" title text: "]; + [description appendText:title_text]; + }; + + return grey_allOf( + grey_kindOfClass([HistoryEntryCell class]), + [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches + descriptionBlock:describe], + grey_sufficientlyVisible(), nil); } // Matcher for the history button in the tools menu. id<GREYMatcher> HistoryButton() { @@ -183,8 +205,12 @@ + (void)setUp { [super setUp]; std::map<GURL, std::string> responses; - responses[web::test::HttpServer::MakeUrl(kURL1)] = kResponse1; - responses[web::test::HttpServer::MakeUrl(kURL2)] = kResponse2; + const char kPageFormat[] = "<head><title>%s</title></head><body>%s</body>"; + responses[web::test::HttpServer::MakeUrl(kURL1)] = + base::StringPrintf(kPageFormat, kTitle1, kResponse1); + responses[web::test::HttpServer::MakeUrl(kURL2)] = + base::StringPrintf(kPageFormat, kTitle2, kResponse2); + // Page 3 does not have <title> tag, so URL will be its title. responses[web::test::HttpServer::MakeUrl(kURL3)] = kResponse3; web::test::SetUpSimpleHttpServer(responses); } @@ -232,19 +258,36 @@ [self openHistoryPanel]; // Assert that history displays three entries. - [[EarlGrey selectElementWithMatcher:HistoryEntryWithUrl(_URL1)] + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL1, kTitle1)] assertWithMatcher:grey_notNil()]; - [[EarlGrey selectElementWithMatcher:HistoryEntryWithUrl(_URL2)] + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL2, kTitle2)] assertWithMatcher:grey_notNil()]; - [[EarlGrey selectElementWithMatcher:HistoryEntryWithUrl(_URL3)] + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL3, _URL3.GetContent())] assertWithMatcher:grey_notNil()]; // Tap a history entry and assert that navigation to that entry's URL occurs. - [[EarlGrey selectElementWithMatcher:HistoryEntryWithUrl(_URL1)] + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL1, kTitle1)] performAction:grey_tap()]; - id<GREYMatcher> webViewMatcher = - chrome_test_util::WebViewContainingText(kResponse1); - [[EarlGrey selectElementWithMatcher:webViewMatcher] + [[EarlGrey selectElementWithMatcher:WebViewContainingText(kResponse1)] + assertWithMatcher:grey_notNil()]; +} + +// Tests that history is not changed after performing back navigation. +// TODO(crbug.com/688047): Enable this test. +- (void)DISABLED_testHistoryUpdateAfterBackNavigation { + [ChromeEarlGrey loadURL:_URL1]; + [ChromeEarlGrey loadURL:_URL2]; + + [[EarlGrey selectElementWithMatcher:chrome_test_util::BackButton()] + performAction:grey_tap()]; + [[EarlGrey selectElementWithMatcher:WebViewContainingText(kResponse1)] + assertWithMatcher:grey_notNil()]; + + [self openHistoryPanel]; + + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL1, kTitle1)] + assertWithMatcher:grey_notNil()]; + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL2, kTitle2)] assertWithMatcher:grey_notNil()]; } @@ -277,8 +320,8 @@ selectElementWithMatcher:grey_kindOfClass([TransparentLinkButton class])] performAction:grey_tap()]; chrome_test_util::AssertMainTabCount(2); - id<GREYMatcher> webViewMatcher = chrome_test_util::WebViewContainingText( - "Sync and view tabs and history across devices"); + id<GREYMatcher> webViewMatcher = + WebViewContainingText("Sync and view tabs and history across devices"); [[EarlGrey selectElementWithMatcher:webViewMatcher] assertWithMatcher:grey_notNil()]; } @@ -294,11 +337,11 @@ [NSString stringWithFormat:@"%s", _URL1.path().c_str()]; [[EarlGrey selectElementWithMatcher:grey_keyWindow()] performAction:grey_typeText(searchString)]; - [[EarlGrey selectElementWithMatcher:HistoryEntryWithUrl(_URL1)] + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL1, kTitle1)] assertWithMatcher:grey_notNil()]; - [[EarlGrey selectElementWithMatcher:HistoryEntryWithUrl(_URL2)] + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL2, kTitle2)] assertWithMatcher:grey_nil()]; - [[EarlGrey selectElementWithMatcher:HistoryEntryWithUrl(_URL3)] + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL3, _URL3.GetContent())] assertWithMatcher:grey_nil()]; } @@ -308,35 +351,35 @@ [self openHistoryPanel]; // Assert that three history elements are present. - [[EarlGrey selectElementWithMatcher:HistoryEntryWithUrl(_URL1)] + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL1, kTitle1)] assertWithMatcher:grey_notNil()]; - [[EarlGrey selectElementWithMatcher:HistoryEntryWithUrl(_URL2)] + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL2, kTitle2)] assertWithMatcher:grey_notNil()]; - [[EarlGrey selectElementWithMatcher:HistoryEntryWithUrl(_URL3)] + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL3, _URL3.GetContent())] assertWithMatcher:grey_notNil()]; // Enter edit mode, select a history element, and press delete. [[EarlGrey selectElementWithMatcher:NavigationEditButton()] performAction:grey_tap()]; - [[EarlGrey selectElementWithMatcher:HistoryEntryWithUrl(_URL1)] + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL1, kTitle1)] performAction:grey_tap()]; [[EarlGrey selectElementWithMatcher:DeleteHistoryEntriesButton()] performAction:grey_tap()]; // Assert that the deleted entry is gone and the other two remain. - [[EarlGrey selectElementWithMatcher:HistoryEntryWithUrl(_URL1)] + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL1, kTitle1)] assertWithMatcher:grey_nil()]; - [[EarlGrey selectElementWithMatcher:HistoryEntryWithUrl(_URL2)] + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL2, kTitle2)] assertWithMatcher:grey_notNil()]; - [[EarlGrey selectElementWithMatcher:HistoryEntryWithUrl(_URL3)] + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL3, _URL3.GetContent())] assertWithMatcher:grey_notNil()]; // Enter edit mode, select both remaining entries, and press delete. [[EarlGrey selectElementWithMatcher:NavigationEditButton()] performAction:grey_tap()]; - [[EarlGrey selectElementWithMatcher:HistoryEntryWithUrl(_URL2)] + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL2, kTitle2)] performAction:grey_tap()]; - [[EarlGrey selectElementWithMatcher:HistoryEntryWithUrl(_URL3)] + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL3, _URL3.GetContent())] performAction:grey_tap()]; [[EarlGrey selectElementWithMatcher:DeleteHistoryEntriesButton()] performAction:grey_tap()]; @@ -383,7 +426,7 @@ [self openHistoryPanel]; // Long press on the history element. - [[EarlGrey selectElementWithMatcher:HistoryEntryWithUrl(_URL1)] + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL1, kTitle1)] performAction:grey_longPress()]; // Select "Open in New Tab" and confirm that new tab is opened with selected @@ -403,7 +446,7 @@ [self openHistoryPanel]; // Long press on the history element. - [[EarlGrey selectElementWithMatcher:HistoryEntryWithUrl(_URL1)] + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL1, kTitle1)] performAction:grey_longPress()]; // Select "Open in New Incognito Tab" and confirm that new tab is opened in @@ -430,7 +473,7 @@ [self openHistoryPanel]; // Long press on the history element. - [[EarlGrey selectElementWithMatcher:HistoryEntryWithUrl(_URL1)] + [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL1, kTitle1)] performAction:grey_longPress()]; // Tap "Copy URL" and wait for the URL to be copied to the pasteboard. @@ -460,21 +503,15 @@ - (void)loadTestURLs { [ChromeEarlGrey loadURL:_URL1]; - id<GREYMatcher> response1Matcher = - chrome_test_util::WebViewContainingText(kResponse1); - [[EarlGrey selectElementWithMatcher:response1Matcher] + [[EarlGrey selectElementWithMatcher:WebViewContainingText(kResponse1)] assertWithMatcher:grey_notNil()]; [ChromeEarlGrey loadURL:_URL2]; - id<GREYMatcher> response2Matcher = - chrome_test_util::WebViewContainingText(kResponse2); - [[EarlGrey selectElementWithMatcher:response2Matcher] + [[EarlGrey selectElementWithMatcher:WebViewContainingText(kResponse2)] assertWithMatcher:grey_notNil()]; [ChromeEarlGrey loadURL:_URL3]; - id<GREYMatcher> response3Matcher = - chrome_test_util::WebViewContainingText(kResponse3); - [[EarlGrey selectElementWithMatcher:response3Matcher] + [[EarlGrey selectElementWithMatcher:WebViewContainingText(kResponse3)] assertWithMatcher:grey_notNil()]; }
diff --git a/ios/chrome/browser/ui/main/browser_view_wrangler.mm b/ios/chrome/browser/ui/main/browser_view_wrangler.mm index b16f003..d0bc024 100644 --- a/ios/chrome/browser/ui/main/browser_view_wrangler.mm +++ b/ios/chrome/browser/ui/main/browser_view_wrangler.mm
@@ -226,7 +226,8 @@ - (void)updateDeviceSharingManager { if (!self.deviceSharingManager) { - self.deviceSharingManager = [[DeviceSharingManager alloc] init]; + self.deviceSharingManager = + [[[DeviceSharingManager alloc] init] autorelease]; } [self.deviceSharingManager updateBrowserState:_browserState];
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/BUILD.gn b/ios/chrome/browser/ui/ntp/recent_tabs/BUILD.gn index e4aaf24..2de4e113 100644 --- a/ios/chrome/browser/ui/ntp/recent_tabs/BUILD.gn +++ b/ios/chrome/browser/ui/ntp/recent_tabs/BUILD.gn
@@ -49,6 +49,7 @@ } source_set("unit_tests") { + configs += [ "//build/config/compiler:enable_arc" ] testonly = true sources = [ "recent_tabs_panel_controller_unittest.mm",
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_panel_controller_unittest.mm b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_panel_controller_unittest.mm index 5337515..db5e7c2c 100644 --- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_panel_controller_unittest.mm +++ b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_panel_controller_unittest.mm
@@ -8,8 +8,6 @@ #include <memory> -#import "base/mac/scoped_nsautorelease_pool.h" -#import "base/mac/scoped_nsobject.h" #include "base/memory/ptr_util.h" #include "components/browser_sync/profile_sync_service.h" #include "components/browser_sync/profile_sync_service_mock.h" @@ -32,6 +30,10 @@ #import "third_party/ocmock/OCMock/OCMock.h" #import "third_party/ocmock/gtest_support.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + using testing::_; using testing::AtLeast; using testing::Return; @@ -124,8 +126,8 @@ EXPECT_CALL(*sync_service, GetOpenTabsUIDelegate()) .WillRepeatedly(Return(nullptr)); - mock_table_view_controller_.reset([[OCMockObject - niceMockForClass:[RecentTabsTableViewController class]] retain]); + mock_table_view_controller_ = + [OCMockObject niceMockForClass:[RecentTabsTableViewController class]]; } void SetupSyncState(BOOL signedIn, @@ -172,10 +174,10 @@ chrome_browser_state_.get())); EXPECT_CALL(*sync_service, AddObserver(_)).Times(AtLeast(1)); EXPECT_CALL(*sync_service, RemoveObserver(_)).Times(AtLeast(1)); - controller_.reset([[RecentTabsPanelController alloc] + controller_ = [[RecentTabsPanelController alloc] initWithController:(RecentTabsTableViewController*) - mock_table_view_controller_.get() - browserState:chrome_browser_state_.get()]); + mock_table_view_controller_ + browserState:chrome_browser_state_.get()]; } protected: @@ -187,19 +189,13 @@ std::unique_ptr<OpenTabsUIDelegateMock> open_tabs_ui_delegate_; // Must be declared *after* |chrome_browser_state_| so it can outlive it. - base::scoped_nsobject<OCMockObject> mock_table_view_controller_; - base::scoped_nsobject<RecentTabsPanelController> controller_; - - // Sets up a private Autorelease Pool so objects retained by OCMockObject - // are released as soon as possible. Otherwise, weak pointers in the - // objects retained by OCMockObject may surface as a BADACC when the - // unit test autorelease pool is released. - base::mac::ScopedNSAutoreleasePool pool_; + OCMockObject* mock_table_view_controller_; + RecentTabsPanelController* controller_; }; TEST_F(RecentTabsPanelControllerTest, TestConstructorDestructor) { CreateController(); - EXPECT_TRUE(controller_.get()); + EXPECT_TRUE(controller_); } TEST_F(RecentTabsPanelControllerTest, TestUserSignedOut) {
diff --git a/ios/chrome/browser/ui/reader_mode/BUILD.gn b/ios/chrome/browser/ui/reader_mode/BUILD.gn index 4916f60..5cd0fb44 100644 --- a/ios/chrome/browser/ui/reader_mode/BUILD.gn +++ b/ios/chrome/browser/ui/reader_mode/BUILD.gn
@@ -3,6 +3,7 @@ # found in the LICENSE file. source_set("reader_mode") { + configs += [ "//build/config/compiler:enable_arc" ] sources = [ "reader_mode_checker.h", "reader_mode_checker.mm",
diff --git a/ios/chrome/browser/ui/reader_mode/reader_mode_checker.mm b/ios/chrome/browser/ui/reader_mode/reader_mode_checker.mm index 8043291..d2ccabaa 100644 --- a/ios/chrome/browser/ui/reader_mode/reader_mode_checker.mm +++ b/ios/chrome/browser/ui/reader_mode/reader_mode_checker.mm
@@ -12,9 +12,14 @@ #include "components/dom_distiller/core/url_utils.h" #include "components/grit/components_resources.h" #include "ios/web/public/web_state/js/crw_js_injection_evaluator.h" +#include "ios/web/public/web_state/js/crw_js_injection_receiver.h" #include "ios/web/public/web_state/web_state.h" #include "ui/base/resource/resource_bundle.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + ReaderModeCheckerObserver::ReaderModeCheckerObserver( ReaderModeChecker* readerModeChecker) : readerModeChecker_(readerModeChecker) {
diff --git a/ios/chrome/browser/ui/reader_mode/reader_mode_controller.mm b/ios/chrome/browser/ui/reader_mode/reader_mode_controller.mm index f04917f..7b34b39 100644 --- a/ios/chrome/browser/ui/reader_mode/reader_mode_controller.mm +++ b/ios/chrome/browser/ui/reader_mode/reader_mode_controller.mm
@@ -7,9 +7,7 @@ #include <memory> #include <utility> -#include "base/ios/weak_nsobject.h" #include "base/mac/bind_objc_block.h" -#include "base/mac/scoped_nsobject.h" #include "base/memory/ptr_util.h" #include "base/strings/sys_string_conversions.h" #include "components/infobars/core/infobar.h" @@ -24,6 +22,10 @@ #include "ios/web/public/browser_state.h" #include "ios/web/public/web_state/web_state.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + @protocol ReaderModeCheckerObserverBridgeProtocol - (void)pageIsDistillable; @end @@ -96,7 +98,7 @@ infobars::InfoBar* infobar_; web::WebState* _webState; } -@property(readonly, nonatomic) id<ReaderModeControllerDelegate> delegate; +@property(weak, readonly, nonatomic) id<ReaderModeControllerDelegate> delegate; // Triggers a distillation and returns a DistillerViewer to keep as a handle to // the running distillation. @@ -142,7 +144,6 @@ - (void)dealloc { if (_webState) [self detachFromWebState]; - [super dealloc]; } - (void)detachFromWebState { @@ -160,7 +161,7 @@ - (std::unique_ptr<dom_distiller::DistillerViewer>)startDistillation { DCHECK(_webState); - base::WeakNSObject<ReaderModeController> weakSelf(self); + __weak ReaderModeController* weakSelf = self; GURL pageURL = _webState->GetLastCommittedURL(); ios::ChromeBrowserState* browserState = ios::ChromeBrowserState::FromBrowserState(_webState->GetBrowserState()); @@ -168,7 +169,7 @@ dom_distiller::DomDistillerServiceFactory::GetForBrowserState( browserState), browserState->GetPrefs(), pageURL, - base::BindBlock(^( + base::BindBlockArc(^( const GURL& pageURL, const std::string& html, const std::vector<dom_distiller::DistillerViewer::ImageInfo>& images, const std::string& title) { @@ -191,7 +192,7 @@ - (ReaderModeView*)readerModeViewWithFrame:(CGRect)frame { DCHECK(_checker->CanSwitchToReaderMode()); ReaderModeView* view = - [[[ReaderModeView alloc] initWithFrame:frame delegate:self] autorelease]; + [[ReaderModeView alloc] initWithFrame:frame delegate:self]; [view assignDistillerViewer:[self startDistillation]]; return view; } @@ -200,14 +201,13 @@ - (void)showInfoBar:(const std::string&)html forURL:(const GURL&)url { DCHECK(_webState); - base::WeakNSProtocol<id<ReaderModeControllerDelegate>> weakDelegate( - self.delegate); + __weak id<ReaderModeControllerDelegate> weakDelegate = self.delegate; // Non reference version of the variables needed. const std::string html_non_ref(html); const GURL url_non_ref(url); auto infoBarDelegate = - base::MakeUnique<ReaderModeInfoBarDelegate>(base::BindBlock(^{ + base::MakeUnique<ReaderModeInfoBarDelegate>(base::BindBlockArc(^{ [weakDelegate loadReaderModeHTML:base::SysUTF8ToNSString(html_non_ref) forURL:url_non_ref]; }));
diff --git a/ios/chrome/browser/ui/reader_mode/reader_mode_infobar_delegate.mm b/ios/chrome/browser/ui/reader_mode/reader_mode_infobar_delegate.mm index fd65a49b..5bacdb61 100644 --- a/ios/chrome/browser/ui/reader_mode/reader_mode_infobar_delegate.mm +++ b/ios/chrome/browser/ui/reader_mode/reader_mode_infobar_delegate.mm
@@ -6,6 +6,10 @@ #include "base/strings/utf_string_conversions.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + ReaderModeInfoBarDelegate::ReaderModeInfoBarDelegate( const base::Closure& callback) : callback_(callback) {}
diff --git a/ios/chrome/browser/ui/reader_mode/reader_mode_view.h b/ios/chrome/browser/ui/reader_mode/reader_mode_view.h index 51ebe97..b98c0a1e 100644 --- a/ios/chrome/browser/ui/reader_mode/reader_mode_view.h +++ b/ios/chrome/browser/ui/reader_mode/reader_mode_view.h
@@ -35,7 +35,7 @@ - (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE; // The view's delegate. -@property(nonatomic, readonly) id<ReaderModeViewDelegate> delegate; +@property(weak, nonatomic, readonly) id<ReaderModeViewDelegate> delegate; // Takes ownership of the viewer as it is the only handle to the distillation: // When freed it cancels the distillation, if it is not finished yet. The
diff --git a/ios/chrome/browser/ui/reader_mode/reader_mode_view.mm b/ios/chrome/browser/ui/reader_mode/reader_mode_view.mm index 471394a..10e886e0 100644 --- a/ios/chrome/browser/ui/reader_mode/reader_mode_view.mm +++ b/ios/chrome/browser/ui/reader_mode/reader_mode_view.mm
@@ -4,12 +4,14 @@ #import "ios/chrome/browser/ui/reader_mode/reader_mode_view.h" -#include "base/mac/objc_property_releaser.h" -#include "base/mac/scoped_nsobject.h" #include "ios/chrome/browser/dom_distiller/distiller_viewer.h" #import "ios/chrome/browser/ui/material_components/activity_indicator.h" #import "ios/third_party/material_components_ios/src/components/ActivityIndicator/src/MaterialActivityIndicator.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace { const CGFloat kCloseButtonSize = 40; const CGFloat kCloseButtonMargin = 10; @@ -19,11 +21,10 @@ @interface ReaderModeView ()<MDCActivityIndicatorDelegate> { std::unique_ptr<dom_distiller::DistillerViewer> _viewer; - base::mac::ObjCPropertyReleaser _propertyReleaser_ReaderModeView; } -@property(nonatomic, retain) MDCActivityIndicator* activityIndicator; +@property(nonatomic, strong) MDCActivityIndicator* activityIndicator; @property(nonatomic, copy) ProceduralBlock animateOutCompletionBlock; -@property(nonatomic, retain) UIButton* closeButton; +@property(nonatomic, strong) UIButton* closeButton; @end @@ -37,7 +38,6 @@ delegate:(id<ReaderModeViewDelegate>)delegate { self = [super initWithFrame:frame]; if (self) { - _propertyReleaser_ReaderModeView.Init(self, [ReaderModeView class]); _delegate = delegate; self.backgroundColor = [UIColor whiteColor]; @@ -45,7 +45,7 @@ self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - _closeButton = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain]; + _closeButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [_closeButton addTarget:self action:@selector(close) forControlEvents:UIControlEventTouchUpInside];
diff --git a/ios/chrome/browser/ui/reading_list/BUILD.gn b/ios/chrome/browser/ui/reading_list/BUILD.gn index bcd8d9ce6..fa75f37d 100644 --- a/ios/chrome/browser/ui/reading_list/BUILD.gn +++ b/ios/chrome/browser/ui/reading_list/BUILD.gn
@@ -48,10 +48,10 @@ "reading_list_side_swipe_provider.mm", "reading_list_toolbar.h", "reading_list_toolbar.mm", + "reading_list_view_controller.h", + "reading_list_view_controller.mm", "reading_list_view_controller_builder.h", "reading_list_view_controller_builder.mm", - "reading_list_view_controller_container.h", - "reading_list_view_controller_container.mm", ] deps = [ ":resources", @@ -97,7 +97,7 @@ sources = [ "offline_page_native_content_unittest.mm", "reading_list_collection_view_controller_unittest.mm", - "reading_list_view_controller_container_unittest.mm", + "reading_list_view_controller_unittest.mm", ] deps = [ ":reading_list", @@ -105,6 +105,7 @@ "//components/favicon/core", "//components/prefs", "//components/reading_list/ios", + "//components/url_formatter", "//ios/chrome/browser/browser_state:test_support", "//ios/chrome/browser/favicon", "//ios/chrome/browser/reading_list",
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller_unittest.mm b/ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller_unittest.mm index 3b3bc237..de8244f 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller_unittest.mm
@@ -10,6 +10,7 @@ #include "base/mac/scoped_nsobject.h" #include "base/memory/ptr_util.h" #include "base/single_thread_task_runner.h" +#include "base/strings/sys_string_conversions.h" #include "base/threading/thread_task_runner_handle.h" #include "components/favicon/core/favicon_client.h" #include "components/favicon/core/favicon_service.h" @@ -17,6 +18,7 @@ #include "components/reading_list/ios/reading_list_model.h" #include "components/reading_list/ios/reading_list_model_impl.h" #include "components/reading_list/ios/reading_list_model_storage.h" +#include "components/url_formatter/url_formatter.h" #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" #include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h" #import "ios/chrome/browser/ui/collection_view/collection_view_model.h" @@ -169,3 +171,60 @@ EXPECT_OCMOCK_VERIFY(mock_delegate_); } + +// Tests that the ReadingListCollectionView is creating +// ReadingListCollectionViewItem with the correct informations. +TEST_F(ReadingListCollectionViewControllerTest, + TestItemInitializationUndistilled) { + // Setup. + GURL url("https://chromium.org"); + std::string title("Chromium"); + reading_list_model_->AddEntry(url, title, + reading_list::ADDED_VIA_CURRENT_APP); + // Load view. + [reading_list_view_controller_ view]; + DCHECK([reading_list_view_controller_.get().collectionView + numberOfItemsInSection:0] == 1); + NSIndexPath* indexPath = [NSIndexPath indexPathForItem:0 inSection:0]; + ReadingListCollectionViewItem* readingListItem = + base::mac::ObjCCastStrict<ReadingListCollectionViewItem>( + [[reading_list_view_controller_ collectionViewModel] + itemAtIndexPath:indexPath]); + EXPECT_EQ(base::SysNSStringToUTF8([readingListItem text]), title); + EXPECT_EQ([readingListItem url], url); + EXPECT_EQ(base::SysNSStringToUTF16([readingListItem detailText]), + url_formatter::FormatUrl(url)); + EXPECT_EQ([readingListItem faviconPageURL], url); + EXPECT_EQ([readingListItem distillationState], ReadingListEntry::WAITING); +} + +// Tests that the ReadingListCollectionView is creating +// ReadingListCollectionViewItem with the correct informations for distilled +// items. +TEST_F(ReadingListCollectionViewControllerTest, + TestItemInitializationDistilled) { + // Setup. + GURL url("https://chromium.org"); + std::string title("Chromium"); + GURL distilled_url("https://chromium.org/distilled"); + base::FilePath distilled_path("/distilled/path"); + reading_list_model_->AddEntry(url, title, + reading_list::ADDED_VIA_CURRENT_APP); + reading_list_model_->SetEntryDistilledInfo(url, distilled_path, + distilled_url); + // Load view. + [reading_list_view_controller_ view]; + DCHECK([reading_list_view_controller_.get().collectionView + numberOfItemsInSection:0] == 1); + NSIndexPath* indexPath = [NSIndexPath indexPathForItem:0 inSection:0]; + ReadingListCollectionViewItem* readingListItem = + base::mac::ObjCCastStrict<ReadingListCollectionViewItem>( + [[reading_list_view_controller_ collectionViewModel] + itemAtIndexPath:indexPath]); + EXPECT_EQ(base::SysNSStringToUTF8([readingListItem text]), title); + EXPECT_EQ([readingListItem url], url); + EXPECT_EQ(base::SysNSStringToUTF16([readingListItem detailText]), + url_formatter::FormatUrl(url)); + EXPECT_EQ([readingListItem faviconPageURL], distilled_url); + EXPECT_EQ([readingListItem distillationState], ReadingListEntry::PROCESSED); +}
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_view_controller_container.h b/ios/chrome/browser/ui/reading_list/reading_list_view_controller.h similarity index 79% rename from ios/chrome/browser/ui/reading_list/reading_list_view_controller_container.h rename to ios/chrome/browser/ui/reading_list/reading_list_view_controller.h index 958cb27a..1904d97 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_view_controller_container.h +++ b/ios/chrome/browser/ui/reading_list/reading_list_view_controller.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_VIEW_CONTROLLER_CONTAINER_H_ -#define IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_VIEW_CONTROLLER_CONTAINER_H_ +#ifndef IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_VIEW_CONTROLLER_H_ +#define IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_VIEW_CONTROLLER_H_ #import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller.h" #import "ios/chrome/browser/ui/reading_list/reading_list_toolbar.h" @@ -17,10 +17,10 @@ class ReadingListModel; @protocol UrlLoader; -// Container for the Reading List View Controller and the toolbar. It handles -// the interactions between the two. It also acts as a ReadingList delegate, -// opening entries and displaying context menu. -@interface ReadingListViewControllerContainer +// Container for the ReadingList Collection View Controller and the toolbar. It +// handles the interactions between the two. It also acts as a ReadingList +// delegate, opening entries and displaying context menu. +@interface ReadingListViewController : UIViewController<ReadingListCollectionViewControllerDelegate> - (instancetype)initWithModel:(ReadingListModel*)model @@ -36,4 +36,4 @@ @end -#endif // IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_VIEW_CONTROLLER_CONTAINER_H_ +#endif // IOS_CHROME_BROWSER_UI_READING_LIST_READING_LIST_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_view_controller_container.mm b/ios/chrome/browser/ui/reading_list/reading_list_view_controller.mm similarity index 97% rename from ios/chrome/browser/ui/reading_list/reading_list_view_controller_container.mm rename to ios/chrome/browser/ui/reading_list/reading_list_view_controller.mm index 841793a..253ce847 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_view_controller_container.mm +++ b/ios/chrome/browser/ui/reading_list/reading_list_view_controller.mm
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "ios/chrome/browser/ui/reading_list/reading_list_view_controller_container.h" +#import "ios/chrome/browser/ui/reading_list/reading_list_view_controller.h" #import <MobileCoreServices/MobileCoreServices.h> @@ -58,9 +58,8 @@ }; } -@interface ReadingListViewControllerContainer ()< - ReadingListToolbarActions, - ReadingListToolbarHeightDelegate> { +@interface ReadingListViewController ()<ReadingListToolbarActions, + ReadingListToolbarHeightDelegate> { // Toolbar with the actions. ReadingListToolbar* _toolbar; // This constraint control the expanded mode of the toolbar. @@ -88,7 +87,7 @@ @end -@implementation ReadingListViewControllerContainer +@implementation ReadingListViewController @synthesize readingListCollectionViewController = _readingListCollectionViewController; @@ -205,7 +204,7 @@ } const GURL entryURL = entry->URL(); - __weak ReadingListViewControllerContainer* weakSelf = self; + __weak ReadingListViewController* weakSelf = self; _alertCoordinator = [[ActionSheetCoordinator alloc] initWithBaseViewController:self @@ -375,7 +374,7 @@ #pragma mark - UIResponder - (NSArray*)keyCommands { - __weak ReadingListViewControllerContainer* weakSelf = self; + __weak ReadingListViewController* weakSelf = self; return @[ [UIKeyCommand cr_keyCommandWithInput:UIKeyInputEscape modifierFlags:Cr_UIKeyModifierNone title:nil
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_view_controller_builder.h b/ios/chrome/browser/ui/reading_list/reading_list_view_controller_builder.h index 9df0a03..bc33b6a 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_view_controller_builder.h +++ b/ios/chrome/browser/ui/reading_list/reading_list_view_controller_builder.h
@@ -7,7 +7,7 @@ #import <UIKit/UIKit.h> -#import "ios/chrome/browser/ui/reading_list/reading_list_view_controller_container.h" +#import "ios/chrome/browser/ui/reading_list/reading_list_view_controller.h" namespace ios { class ChromeBrowserState; @@ -21,7 +21,7 @@ // A builder class that constructs ReadingListViewControllers. @interface ReadingListViewControllerBuilder : NSObject -+ (ReadingListViewControllerContainer*) ++ (ReadingListViewController*) readingListViewControllerInBrowserState:(ios::ChromeBrowserState*)browserState loader:(id<UrlLoader>)loader;
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_view_controller_builder.mm b/ios/chrome/browser/ui/reading_list/reading_list_view_controller_builder.mm index d396d44..1c0df38 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_view_controller_builder.mm +++ b/ios/chrome/browser/ui/reading_list/reading_list_view_controller_builder.mm
@@ -18,7 +18,7 @@ @implementation ReadingListViewControllerBuilder -+ (ReadingListViewControllerContainer*) ++ (ReadingListViewController*) readingListViewControllerInBrowserState:(ios::ChromeBrowserState*)browserState loader:(id<UrlLoader>)loader { ReadingListModel* model = @@ -28,11 +28,11 @@ ReadingListDownloadService* rlservice = ReadingListDownloadServiceFactory::GetInstance()->GetForBrowserState( browserState); - ReadingListViewControllerContainer* vc = - [[ReadingListViewControllerContainer alloc] initWithModel:model - loader:loader - largeIconService:service - readingListDownloadService:rlservice]; + ReadingListViewController* vc = + [[ReadingListViewController alloc] initWithModel:model + loader:loader + largeIconService:service + readingListDownloadService:rlservice]; return vc; }
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_view_controller_container_unittest.mm b/ios/chrome/browser/ui/reading_list/reading_list_view_controller_unittest.mm similarity index 91% rename from ios/chrome/browser/ui/reading_list/reading_list_view_controller_container_unittest.mm rename to ios/chrome/browser/ui/reading_list/reading_list_view_controller_unittest.mm index c7a1631..d41a48d7 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_view_controller_container_unittest.mm +++ b/ios/chrome/browser/ui/reading_list/reading_list_view_controller_unittest.mm
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "ios/chrome/browser/ui/reading_list/reading_list_view_controller_container.h" +#import "ios/chrome/browser/ui/reading_list/reading_list_view_controller.h" #include "base/mac/scoped_nsobject.h" #include "base/memory/ptr_util.h" @@ -110,26 +110,26 @@ @end -#pragma mark - ReadingListViewControllerContainerTest +#pragma mark - ReadingListViewControllerTest -class ReadingListViewControllerContainerTest : public web::WebTestWithWebState { +class ReadingListViewControllerTest : public web::WebTestWithWebState { public: - ReadingListViewControllerContainerTest() { + ReadingListViewControllerTest() { loader_mock_.reset([[UrlLoaderStub alloc] init]); mock_favicon_service_.reset(new MockFaviconService()); reading_list_model_.reset(new ReadingListModelImpl(nullptr, nullptr)); large_icon_service_.reset(new favicon::LargeIconService( mock_favicon_service_.get(), base::ThreadTaskRunnerHandle::Get())); - container_.reset([[ReadingListViewControllerContainer alloc] + container_.reset([[ReadingListViewController alloc] initWithModel:reading_list_model_.get() loader:loader_mock_ largeIconService:large_icon_service_.get() readingListDownloadService:nil]); } - ~ReadingListViewControllerContainerTest() override {} + ~ReadingListViewControllerTest() override {} - ReadingListViewControllerContainer* GetContainer() { return container_; } + ReadingListViewController* GetContainer() { return container_; } ReadingListModel* GetReadingListModel() { return reading_list_model_.get(); } UrlLoaderStub* GetLoaderStub() { return loader_mock_; } @@ -143,7 +143,7 @@ } private: - base::scoped_nsobject<ReadingListViewControllerContainer> container_; + base::scoped_nsobject<ReadingListViewController> container_; std::unique_ptr<ReadingListModelImpl> reading_list_model_; base::scoped_nsobject<UrlLoaderStub> loader_mock_; std::unique_ptr<favicon::LargeIconService> large_icon_service_; @@ -152,7 +152,7 @@ // Tests that the implementation of ReadingListCollectionViewController // openItemAtIndexPath opens the entry. -TEST_F(ReadingListViewControllerContainerTest, OpenItem) { +TEST_F(ReadingListViewControllerTest, OpenItem) { // Setup. GURL url("https://chromium.org"); std::string title("Chromium");
diff --git a/ios/chrome/browser/ui/webui/OWNERS b/ios/chrome/browser/ui/webui/OWNERS index a01ab6c..be9def2 100644 --- a/ios/chrome/browser/ui/webui/OWNERS +++ b/ios/chrome/browser/ui/webui/OWNERS
@@ -1,2 +1,5 @@ eugenebut@chromium.org michaeldo@chromium.org + +per-file ntp_tiles_internals_ui.*=file://components/ntp_tiles/OWNERS +per-file popular_sites_internals_ui.*=file://components/ntp_tiles/OWNERS
diff --git a/ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc b/ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc index 5f39a694..8c3753a 100644 --- a/ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc +++ b/ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc
@@ -8,7 +8,6 @@ #include "components/grit/components_resources.h" #include "components/ntp_tiles/field_trial.h" #include "components/ntp_tiles/most_visited_sites.h" -#include "components/ntp_tiles/popular_sites.h" #include "components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h" #include "components/ntp_tiles/webui/ntp_tiles_internals_message_handler_client.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" @@ -37,7 +36,6 @@ bool SupportsNTPTiles() override; bool DoesSourceExist(ntp_tiles::NTPTileSource source) override; std::unique_ptr<ntp_tiles::MostVisitedSites> MakeMostVisitedSites() override; - std::unique_ptr<ntp_tiles::PopularSites> MakePopularSites() override; PrefService* GetPrefs() override; void RegisterMessageCallback( const std::string& message, @@ -80,12 +78,6 @@ ios::ChromeBrowserState::FromWebUIIOS(web_ui())); } -std::unique_ptr<ntp_tiles::PopularSites> -IOSNTPTilesInternalsMessageHandlerBridge::MakePopularSites() { - return IOSPopularSitesFactory::NewForBrowserState( - ios::ChromeBrowserState::FromWebUIIOS(web_ui())); -} - PrefService* IOSNTPTilesInternalsMessageHandlerBridge::GetPrefs() { return ios::ChromeBrowserState::FromWebUIIOS(web_ui())->GetPrefs(); } @@ -102,8 +94,6 @@ web_ui()->CallJavascriptFunction(name, values); } -} // namespace - web::WebUIIOSDataSource* CreateNTPTilesInternalsHTMLSource() { web::WebUIIOSDataSource* source = web::WebUIIOSDataSource::Create(kChromeUINTPTilesInternalsHost); @@ -115,6 +105,8 @@ return source; } +} // namespace + NTPTilesInternalsUI::NTPTilesInternalsUI(web::WebUIIOS* web_ui) : web::WebUIIOSController(web_ui) { web::WebUIIOSDataSource::Add(ios::ChromeBrowserState::FromWebUIIOS(web_ui),
diff --git a/ios/chrome/browser/ui/webui/popular_sites_internals_ui.cc b/ios/chrome/browser/ui/webui/popular_sites_internals_ui.cc index e07a780..d06f078 100644 --- a/ios/chrome/browser/ui/webui/popular_sites_internals_ui.cc +++ b/ios/chrome/browser/ui/webui/popular_sites_internals_ui.cc
@@ -31,7 +31,6 @@ void RegisterMessages() override; // ntp_tiles::PopularSitesInternalsMessageHandlerClient - base::SequencedWorkerPool* GetBlockingPool() override; std::unique_ptr<ntp_tiles::PopularSites> MakePopularSites() override; PrefService* GetPrefs() override; void RegisterMessageCallback( @@ -50,11 +49,6 @@ handler_.RegisterMessages(); } -base::SequencedWorkerPool* -IOSPopularSitesInternalsMessageHandlerBridge::GetBlockingPool() { - return web::WebThread::GetBlockingPool(); -} - std::unique_ptr<ntp_tiles::PopularSites> IOSPopularSitesInternalsMessageHandlerBridge::MakePopularSites() { return IOSPopularSitesFactory::NewForBrowserState(
diff --git a/ios/chrome/browser/web/browsing_egtest.mm b/ios/chrome/browser/web/browsing_egtest.mm index bb7d308..24657f1 100644 --- a/ios/chrome/browser/web/browsing_egtest.mm +++ b/ios/chrome/browser/web/browsing_egtest.mm
@@ -279,7 +279,9 @@ // Tests that clicking a link with URL changed by onclick uses the href of the // anchor tag instead of the one specified in JavaScript. Also verifies a new // tab is opened by target '_blank'. -- (void)testBrowsingPreventDefaultWithLinkOpenedByJavascript { +// TODO(crbug.com/688223): WKWebView does not open a new window as expected by +// this test. +- (void)DISABLED_testBrowsingPreventDefaultWithLinkOpenedByJavascript { // Create map of canned responses and set up the test HTML server. std::map<GURL, std::string> responses; const GURL URL = web::test::HttpServer::MakeUrl(
diff --git a/ios/chrome/browser/web/window_open_by_dom_egtest.mm b/ios/chrome/browser/web/window_open_by_dom_egtest.mm index 91dd4fa74..8e20f54e 100644 --- a/ios/chrome/browser/web/window_open_by_dom_egtest.mm +++ b/ios/chrome/browser/web/window_open_by_dom_egtest.mm
@@ -60,10 +60,9 @@ AssertMainTabCount(1); } -// Tests that |sessionStorage| content is available for windows opened by DOM -// via |target="_blank"| links. -// TODO(crbug.com/681434): Enable this test. -- (void)DISABLED_testLinkWithBlankTargetSessionStorage { +// Tests that sessionStorage content is available for windows opened by DOM via +// target="_blank" links. +- (void)testLinkWithBlankTargetSessionStorage { using chrome_test_util::ExecuteJavaScript; NSError* error = nil;
diff --git a/ios/clean/DEPS b/ios/clean/DEPS index 7973743..e06ba51 100644 --- a/ios/clean/DEPS +++ b/ios/clean/DEPS
@@ -3,5 +3,6 @@ "+ui/base", "+ios/chrome", "+ios/shared", + "+ios/third_party", "+ios/web", ]
diff --git a/ios/clean/chrome/browser/ui/tab_grid/BUILD.gn b/ios/clean/chrome/browser/ui/tab_grid/BUILD.gn index bbdf558..0cdde28 100644 --- a/ios/clean/chrome/browser/ui/tab_grid/BUILD.gn +++ b/ios/clean/chrome/browser/ui/tab_grid/BUILD.gn
@@ -27,6 +27,8 @@ source_set("tab_grid_ui") { sources = [ + "mdc_floating_button+cr_tab_grid.h", + "mdc_floating_button+cr_tab_grid.mm", "tab_grid_tab_cell.h", "tab_grid_tab_cell.mm", "tab_grid_view_controller.h", @@ -37,9 +39,14 @@ deps = [ "//base", + "//ios/chrome/app/strings", + "//ios/chrome/browser/ui", + "//ios/chrome/browser/ui/colors", "//ios/chrome/browser/ui/tab_switcher", "//ios/clean/chrome/browser/ui/actions", "//ios/clean/chrome/browser/ui/animators", "//ios/clean/chrome/browser/ui/commands", + "//ios/third_party/material_components_ios:material_components_ios", + "//ui/base", ] }
diff --git a/ios/clean/chrome/browser/ui/tab_grid/mdc_floating_button+cr_tab_grid.h b/ios/clean/chrome/browser/ui/tab_grid/mdc_floating_button+cr_tab_grid.h new file mode 100644 index 0000000..65c4042 --- /dev/null +++ b/ios/clean/chrome/browser/ui/tab_grid/mdc_floating_button+cr_tab_grid.h
@@ -0,0 +1,22 @@ +// 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 IOS_CLEAN_CHROME_BROWSER_UI_TAB_GRID_MDC_FLOATING_BUTTON_CR_TAB_GRID_H_ +#define IOS_CLEAN_CHROME_BROWSER_UI_TAB_GRID_MDC_FLOATING_BUTTON_CR_TAB_GRID_H_ + +#import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h" + +// This category provides default styling for floating buttons used in TabGrid. +@interface MDCFloatingButton (CRTabGrid) + +// Constructs floating button with styling defaults for new tab button in tab +// grid. ++ (instancetype)cr_tabGridNewTabButton; + +// Rect for placement of floating button inside lower right corner of |rect|. ++ (CGRect)cr_frameForTabGridNewTabButtonInRect:(CGRect)rect; + +@end + +#endif // IOS_CLEAN_CHROME_BROWSER_UI_TAB_GRID_MDC_FLOATING_BUTTON_CR_TAB_GRID_H_
diff --git a/ios/clean/chrome/browser/ui/tab_grid/mdc_floating_button+cr_tab_grid.mm b/ios/clean/chrome/browser/ui/tab_grid/mdc_floating_button+cr_tab_grid.mm new file mode 100644 index 0000000..91f8724a --- /dev/null +++ b/ios/clean/chrome/browser/ui/tab_grid/mdc_floating_button+cr_tab_grid.mm
@@ -0,0 +1,60 @@ +// 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. + +#import "ios/clean/chrome/browser/ui/tab_grid/mdc_floating_button+cr_tab_grid.h" + +#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" +#include "ios/chrome/browser/ui/rtl_geometry.h" +#include "ios/chrome/grit/ios_strings.h" +#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h" +#include "ui/base/l10n/l10n_util.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace { +// Margin from trailing and bottom edges. +const CGFloat kNewTabButtonMarginFromEdges = 48; + +// Diameter of circular button. +const CGFloat kNewTabButtonDiameter = 48; +} + +@implementation MDCFloatingButton (CRTabGrid) + ++ (instancetype)cr_tabGridNewTabButton { + MDCFloatingButton* button = [[self alloc] init]; + if (button) { + UIImage* openNewTabButtonImage = + [[UIImage imageNamed:@"tabswitcher_new_tab_fab"] + imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + [button setImage:openNewTabButtonImage forState:UIControlStateNormal]; + [[button imageView] setTintColor:[UIColor whiteColor]]; + [button setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin | + UIViewAutoresizingFlexibleLeadingMargin()]; + + MDCPalette* palette = [MDCPalette cr_bluePalette]; + [button setInkColor:[[palette tint300] colorWithAlphaComponent:0.5f]]; + [button setBackgroundColor:[palette tint500] forState:UIControlStateNormal]; + [button setBackgroundColor:[UIColor colorWithWhite:0.8f alpha:1.0f] + forState:UIControlStateDisabled]; + [button setAccessibilityLabel:l10n_util::GetNSString( + IDS_IOS_TAB_SWITCHER_CREATE_NEW_TAB)]; + } + return button; +} + ++ (CGRect)cr_frameForTabGridNewTabButtonInRect:(CGRect)rect { + CGFloat yOrigin = CGRectGetHeight(rect) - kNewTabButtonMarginFromEdges - + kNewTabButtonDiameter; + CGFloat leading = CGRectGetWidth(rect) - kNewTabButtonMarginFromEdges - + kNewTabButtonDiameter; + LayoutRect buttonLayout = + LayoutRectMake(leading, CGRectGetWidth(rect), yOrigin, + kNewTabButtonDiameter, kNewTabButtonDiameter); + return LayoutRectGetRect(buttonLayout); +} + +@end
diff --git a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm index 0d20e73..a599f72 100644 --- a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm +++ b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
@@ -16,6 +16,7 @@ #import "ios/clean/chrome/browser/ui/commands/settings_commands.h" #import "ios/clean/chrome/browser/ui/commands/tab_commands.h" #import "ios/clean/chrome/browser/ui/commands/tab_grid_commands.h" +#import "ios/clean/chrome/browser/ui/tab_grid/mdc_floating_button+cr_tab_grid.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -32,6 +33,7 @@ UICollectionViewDelegate, SessionCellDelegate> @property(nonatomic, weak) UICollectionView* grid; +@property(nonatomic, strong) MDCFloatingButton* floatingNewTabButton; @end @implementation TabGridViewController @@ -41,6 +43,7 @@ @synthesize tabGridCommandHandler = _tabGridCommandHandler; @synthesize tabCommandHandler = _tabCommandHandler; @synthesize grid = _grid; +@synthesize floatingNewTabButton = _floatingNewTabButton; - (void)viewDidLoad { // Placeholder dark grey stripe at the top of the view. @@ -98,6 +101,11 @@ - (void)viewWillAppear:(BOOL)animated { [self.grid reloadData]; + self.floatingNewTabButton = [MDCFloatingButton cr_tabGridNewTabButton]; + [self.floatingNewTabButton + setFrame:[MDCFloatingButton + cr_frameForTabGridNewTabButtonInRect:self.view.bounds]]; + [self.view addSubview:self.floatingNewTabButton]; } #pragma mark - UICollectionViewDataSource methods
diff --git a/ios/clean/chrome/browser/ui/web_contents/BUILD.gn b/ios/clean/chrome/browser/ui/web_contents/BUILD.gn index 13a0a73..6c6553b 100644 --- a/ios/clean/chrome/browser/ui/web_contents/BUILD.gn +++ b/ios/clean/chrome/browser/ui/web_contents/BUILD.gn
@@ -4,8 +4,8 @@ source_set("web_contents") { sources = [ - "web_contents_view_controller.h", - "web_contents_view_controller.mm", + "web_contents_mediator.h", + "web_contents_mediator.mm", "web_coordinator.h", "web_coordinator.mm", ] @@ -13,6 +13,7 @@ configs += [ "//build/config/compiler:enable_arc" ] deps = [ + ":web_contents_ui", "//ios/clean/chrome/browser", "//ios/shared/chrome/browser/coordinator_context", "//ios/web", @@ -20,3 +21,32 @@ "//url", ] } + +source_set("web_contents_ui") { + sources = [ + "web_contents_consumer.h", + "web_contents_view_controller.h", + "web_contents_view_controller.mm", + ] + + configs += [ "//build/config/compiler:enable_arc" ] +} + +source_set("unit_tests") { + testonly = true + sources = [ + "web_contents_mediator_unittest.mm", + ] + + configs += [ "//build/config/compiler:enable_arc" ] + + deps = [ + ":web_contents", + ":web_contents_ui", + "//base", + "//base/test:test_support", + "//ios/chrome/test/base", + "//ios/web:test_support", + "//testing/gtest", + ] +}
diff --git a/ios/clean/chrome/browser/ui/web_contents/web_contents_consumer.h b/ios/clean/chrome/browser/ui/web_contents/web_contents_consumer.h new file mode 100644 index 0000000..6b37647 --- /dev/null +++ b/ios/clean/chrome/browser/ui/web_contents/web_contents_consumer.h
@@ -0,0 +1,17 @@ +// 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 IOS_CLEAN_CHROME_BROWSER_UI_WEB_CONTENTS_WEB_CONTENTS_CONSUMER_H_ +#define IOS_CLEAN_CHROME_BROWSER_UI_WEB_CONTENTS_WEB_CONTENTS_CONSUMER_H_ + +#import <UIKit/UIKit.h> + +// A WebContentsConsumer (typically a view controller) uses data provided by +// this protocol to display a web view. +@protocol WebContentsConsumer +// Called when the content view that the reciever should display changes. +- (void)contentViewDidChange:(UIView*)contentView; +@end + +#endif // IOS_CLEAN_CHROME_BROWSER_UI_WEB_CONTENTS_WEB_CONTENTS_CONSUMER_H_
diff --git a/ios/clean/chrome/browser/ui/web_contents/web_contents_mediator.h b/ios/clean/chrome/browser/ui/web_contents/web_contents_mediator.h new file mode 100644 index 0000000..7ae38a0 --- /dev/null +++ b/ios/clean/chrome/browser/ui/web_contents/web_contents_mediator.h
@@ -0,0 +1,30 @@ +// 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 IOS_CLEAN_CHROME_BROWSER_UI_WEB_CONTENTS_WEB_CONTENTS_MEDIATOR_H_ +#define IOS_CLEAN_CHROME_BROWSER_UI_WEB_CONTENTS_WEB_CONTENTS_MEDIATOR_H_ + +#import <Foundation/Foundation.h> + +@protocol WebContentsConsumer; + +namespace web { +class WebState; +} + +// A mediator object that provides the relevant properties of a web state +// to a consumer. +@interface WebContentsMediator : NSObject + +// The WebState whose properties this object mediates. This can change during +// the lifetime of this object and may be null. +@property(nonatomic, assign) web::WebState* webState; + +// The consumer for this object. This can change during the lifetime of this +// object and may be nil. +@property(nonatomic, weak) id<WebContentsConsumer> consumer; + +@end + +#endif // IOS_CLEAN_CHROME_BROWSER_UI_WEB_CONTENTS_WEB_CONTENTS_MEDIATOR_H_
diff --git a/ios/clean/chrome/browser/ui/web_contents/web_contents_mediator.mm b/ios/clean/chrome/browser/ui/web_contents/web_contents_mediator.mm new file mode 100644 index 0000000..2a5529bc --- /dev/null +++ b/ios/clean/chrome/browser/ui/web_contents/web_contents_mediator.mm
@@ -0,0 +1,45 @@ +// 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. + +#import "ios/clean/chrome/browser/ui/web_contents/web_contents_mediator.h" + +#import "ios/clean/chrome/browser/ui/web_contents/web_contents_consumer.h" +#import "ios/web/public/navigation_manager.h" +#include "ios/web/public/web_state/web_state.h" +#include "ui/base/page_transition_types.h" +#include "url/gurl.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@implementation WebContentsMediator +@synthesize webState = _webState; +@synthesize consumer = _consumer; + +- (void)setWebState:(web::WebState*)webState { + if (_webState) + _webState->SetWebUsageEnabled(false); + + _webState = webState; + if (!self.webState) + return; + + self.webState->SetWebUsageEnabled(true); + if (!self.webState->GetNavigationManager()->GetItemCount()) { + web::NavigationManager::WebLoadParams params( + GURL("https://dev.chromium.org/")); + params.transition_type = ui::PAGE_TRANSITION_TYPED; + self.webState->GetNavigationManager()->LoadURLWithParams(params); + } + [self.consumer contentViewDidChange:self.webState->GetView()]; +} + +- (void)setConsumer:(id<WebContentsConsumer>)consumer { + _consumer = consumer; + if (self.webState) + [self.consumer contentViewDidChange:self.webState->GetView()]; +} + +@end
diff --git a/ios/clean/chrome/browser/ui/web_contents/web_contents_mediator_unittest.mm b/ios/clean/chrome/browser/ui/web_contents/web_contents_mediator_unittest.mm new file mode 100644 index 0000000..e1cc86f --- /dev/null +++ b/ios/clean/chrome/browser/ui/web_contents/web_contents_mediator_unittest.mm
@@ -0,0 +1,111 @@ +// 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. + +#import "ios/clean/chrome/browser/ui/web_contents/web_contents_mediator.h" + +#include "base/memory/ptr_util.h" +#import "ios/clean/chrome/browser/ui/web_contents/web_contents_consumer.h" +#import "ios/web/public/test/fakes/test_navigation_manager.h" +#import "ios/web/public/test/fakes/test_web_state.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/gtest_mac.h" +#include "testing/platform_test.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@interface StubContentsConsumer : NSObject<WebContentsConsumer> +@property(nonatomic, weak) UIView* contentView; +@end + +@implementation StubContentsConsumer +@synthesize contentView = _contentView; + +- (void)contentViewDidChange:(UIView*)contentView { + self.contentView = contentView; +} + +@end + +namespace { + +class StubNavigationManager : public web::TestNavigationManager { + public: + int GetItemCount() const override { return item_count_; } + + void LoadURLWithParams(const NavigationManager::WebLoadParams&) override { + has_loaded_url_ = true; + } + + void SetItemCount(int count) { item_count_ = count; } + bool GetHasLoadedUrl() { return has_loaded_url_; } + + private: + int item_count_; + bool has_loaded_url_; +}; + +class WebContentsMediatorTest : public PlatformTest { + public: + WebContentsMediatorTest() { + auto navigation_manager = base::MakeUnique<StubNavigationManager>(); + navigation_manager_ = navigation_manager.get(); + navigation_manager_->SetItemCount(0); + web_state_.SetNavigationManager(std::move(navigation_manager)); + } + + protected: + StubNavigationManager* navigation_manager_; + web::TestWebState web_state_; +}; + +TEST_F(WebContentsMediatorTest, TestSetWebUsageEnabled) { + WebContentsMediator* mediator = [[WebContentsMediator alloc] init]; + + mediator.webState = &web_state_; + // Setting the webState should set webUsageEnabled. + EXPECT_EQ(true, web_state_.IsWebUsageEnabled()); + // Expect that with zero navigation items, a url will be loaded. + EXPECT_EQ(true, navigation_manager_->GetHasLoadedUrl()); + + mediator.webState = nullptr; + // The previous webState should now have web usage disabled. + EXPECT_EQ(false, web_state_.IsWebUsageEnabled()); +} + +TEST_F(WebContentsMediatorTest, TestNoLoadURL) { + WebContentsMediator* mediator = [[WebContentsMediator alloc] init]; + + navigation_manager_->SetItemCount(2); + + mediator.webState = &web_state_; + // Expect that with nonzero navigation items, no url will be loaded. + EXPECT_EQ(false, navigation_manager_->GetHasLoadedUrl()); +} + +TEST_F(WebContentsMediatorTest, TestSetWebStateFirst) { + WebContentsMediator* mediator = [[WebContentsMediator alloc] init]; + StubContentsConsumer* consumer = [[StubContentsConsumer alloc] init]; + + mediator.webState = &web_state_; + mediator.consumer = consumer; + + // Setting the consumer after the web state should still have the consumer + // called. + EXPECT_EQ(web_state_.GetView(), consumer.contentView); +} + +TEST_F(WebContentsMediatorTest, TestSetConsumerFirst) { + WebContentsMediator* mediator = [[WebContentsMediator alloc] init]; + StubContentsConsumer* consumer = [[StubContentsConsumer alloc] init]; + + mediator.consumer = consumer; + mediator.webState = &web_state_; + + // Setting the web_state after the consumer should trigger a call to the + // consumer. + EXPECT_EQ(web_state_.GetView(), consumer.contentView); +} +}
diff --git a/ios/clean/chrome/browser/ui/web_contents/web_contents_view_controller.h b/ios/clean/chrome/browser/ui/web_contents/web_contents_view_controller.h index 7faed63..110b385 100644 --- a/ios/clean/chrome/browser/ui/web_contents/web_contents_view_controller.h +++ b/ios/clean/chrome/browser/ui/web_contents/web_contents_view_controller.h
@@ -11,28 +11,11 @@ #import <UIKit/UIKit.h> -namespace web { -class WebState; -} +#import "ios/clean/chrome/browser/ui/web_contents/web_contents_consumer.h" // A view controller for displaying a web view with no other controls or // decoration. -@interface WebContentsViewController : UIViewController - -// Designated initializer. |webState| must not be null. -- (instancetype)initWithWebState:(web::WebState*)webState - NS_DESIGNATED_INITIALIZER; - -- (instancetype)init NS_UNAVAILABLE; - -- (instancetype)initWithCoder:(NSCoder*)aCoder NS_UNAVAILABLE; - -- (instancetype)initWithNibName:(NSString*)nibNameOrNil - bundle:(NSBundle*)nibBundleOrNil NS_UNAVAILABLE; - -// The webState the receiver was initialized with. -@property(nonatomic, readonly) web::WebState* webState; - +@interface WebContentsViewController : UIViewController<WebContentsConsumer> @end #endif // IOS_CLEAN_CHROME_BROWSER_UI_WEB_CONTENTS_WEB_CONTENTS_VIEW_CONTROLLER_H_
diff --git a/ios/clean/chrome/browser/ui/web_contents/web_contents_view_controller.mm b/ios/clean/chrome/browser/ui/web_contents/web_contents_view_controller.mm index 1b9c41d..5ab859d 100644 --- a/ios/clean/chrome/browser/ui/web_contents/web_contents_view_controller.mm +++ b/ios/clean/chrome/browser/ui/web_contents/web_contents_view_controller.mm
@@ -8,49 +8,48 @@ #import "ios/clean/chrome/browser/ui/web_contents/web_contents_view_controller.h" -#import "ios/web/public/navigation_manager.h" -#include "ios/web/public/web_state/web_state.h" -#include "ui/base/page_transition_types.h" -#include "url/gurl.h" - #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif +@interface WebContentsViewController () +@property(nonatomic, strong) UIView* contentView; +@end + @implementation WebContentsViewController -@synthesize webState = _webState; - -- (instancetype)initWithWebState:(web::WebState*)webState { - if ((self = [super initWithNibName:nil bundle:nil])) { - DCHECK(webState); - _webState = webState; - } - return self; -} +@synthesize contentView = _contentView; - (void)viewDidLoad { self.view.backgroundColor = [UIColor colorWithWhite:0.75 alpha:1.0]; - UIView* webContentsView = self.webState->GetView(); - webContentsView.translatesAutoresizingMaskIntoConstraints = NO; - [self.view addSubview:webContentsView]; - [NSLayoutConstraint activateConstraints:@[ - [webContentsView.topAnchor constraintEqualToAnchor:self.view.topAnchor], - [webContentsView.bottomAnchor - constraintEqualToAnchor:self.view.bottomAnchor], - [webContentsView.leadingAnchor - constraintEqualToAnchor:self.view.leadingAnchor], - [webContentsView.trailingAnchor - constraintEqualToAnchor:self.view.trailingAnchor], - ]]; + [self updateContentView]; +} - if (!self.webState->GetNavigationManager()->GetItemCount()) { - web::NavigationManager::WebLoadParams params( - GURL("https://dev.chromium.org/")); - params.transition_type = ui::PAGE_TRANSITION_TYPED; - _webState->GetNavigationManager()->LoadURLWithParams(params); - } +#pragma mark - WebContentsConsumer + +- (void)contentViewDidChange:(UIView*)contentView { + if (contentView == self.contentView) + return; + + // If there was a previous content view, remove it from the view hierarchy. + [self.contentView removeFromSuperview]; + self.contentView = contentView; + + // If self.view hasn't loaded yet, this call shouldn't induce that load. + // (calling self.view will trigger -loadView, etc.). Only update for the + // new content view if there's a view to update. + if (self.viewIfLoaded) + [self updateContentView]; +} + +#pragma mark - Private methods + +- (void)updateContentView { + self.contentView.frame = self.view.bounds; + self.contentView.autoresizingMask = + UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.view addSubview:self.contentView]; } @end
diff --git a/ios/clean/chrome/browser/ui/web_contents/web_coordinator.mm b/ios/clean/chrome/browser/ui/web_contents/web_coordinator.mm index 09d356f6..f736feb 100644 --- a/ios/clean/chrome/browser/ui/web_contents/web_coordinator.mm +++ b/ios/clean/chrome/browser/ui/web_contents/web_coordinator.mm
@@ -9,6 +9,7 @@ #import "ios/clean/chrome/browser/ui/web_contents/web_coordinator.h" #import "ios/clean/chrome/browser/browser_coordinator+internal.h" +#import "ios/clean/chrome/browser/ui/web_contents/web_contents_mediator.h" #import "ios/clean/chrome/browser/ui/web_contents/web_contents_view_controller.h" #import "ios/shared/chrome/browser/coordinator_context/coordinator_context.h" #include "ios/web/public/web_state/web_state.h" @@ -18,19 +19,30 @@ #endif @interface WebCoordinator () - @property(nonatomic, strong) WebContentsViewController* viewController; - +@property(nonatomic, strong) WebContentsMediator* mediator; @end @implementation WebCoordinator @synthesize webState = _webState; @synthesize viewController = _viewController; +@synthesize mediator = _mediator; + +- (instancetype)init { + if ((self = [super init])) { + _mediator = [[WebContentsMediator alloc] init]; + } + return self; +} + +- (void)setWebState:(web::WebState*)webState { + _webState = webState; + self.mediator.webState = self.webState; +} - (void)start { - self.webState->SetWebUsageEnabled(true); - self.viewController = - [[WebContentsViewController alloc] initWithWebState:self.webState]; + self.viewController = [[WebContentsViewController alloc] init]; + self.mediator.consumer = self.viewController; // Reminder: this is a no-op if |baseViewController| is nil, for example // when this coordinator's view controller will be contained instead of @@ -41,7 +53,9 @@ } - (void)stop { - self.webState->SetWebUsageEnabled(false); + // PLACEHOLDER: This is how the webUsageEnabled is set to false. Find a + // better way in the future. + self.mediator.webState = nullptr; } @end
diff --git a/ios/clean/chrome/test/BUILD.gn b/ios/clean/chrome/test/BUILD.gn index f4231655..4ea23cac 100644 --- a/ios/clean/chrome/test/BUILD.gn +++ b/ios/clean/chrome/test/BUILD.gn
@@ -15,5 +15,6 @@ deps = [ "//ios/chrome/test:run_all_unittests", "//ios/clean/chrome/browser:unit_tests", + "//ios/clean/chrome/browser/ui/web_contents:unit_tests", ] }
diff --git a/ios/web/public/web_thread.h b/ios/web/public/web_thread.h index 56cbb21..b5234461 100644 --- a/ios/web/public/web_thread.h +++ b/ios/web/public/web_thread.h
@@ -6,8 +6,9 @@ #define IOS_WEB_PUBLIC_WEB_THREAD_H_ #include <string> +#include <utility> -#include "base/callback_forward.h" +#include "base/callback.h" #include "base/compiler_specific.h" #include "base/location.h" #include "base/logging.h" @@ -116,19 +117,19 @@ static bool PostTaskAndReply(ID identifier, const tracked_objects::Location& from_here, - const base::Closure& task, - const base::Closure& reply); + base::Closure task, + base::Closure reply); template <typename ReturnType, typename ReplyArgType> static bool PostTaskAndReplyWithResult( ID identifier, const tracked_objects::Location& from_here, - const base::Callback<ReturnType(void)>& task, - const base::Callback<void(ReplyArgType)>& reply) { + base::Callback<ReturnType()> task, + base::Callback<void(ReplyArgType)> reply) { scoped_refptr<base::SingleThreadTaskRunner> task_runner = GetTaskRunnerForThread(identifier); - return base::PostTaskAndReplyWithResult(task_runner.get(), from_here, task, - reply); + return base::PostTaskAndReplyWithResult(task_runner.get(), from_here, + std::move(task), std::move(reply)); } template <class T> @@ -163,8 +164,8 @@ const base::Closure& task); static bool PostBlockingPoolTaskAndReply( const tracked_objects::Location& from_here, - const base::Closure& task, - const base::Closure& reply); + base::Closure task, + base::Closure reply); static bool PostBlockingPoolSequencedTask( const std::string& sequence_token_name, const tracked_objects::Location& from_here,
diff --git a/ios/web/web_state/js/resources/core.js b/ios/web/web_state/js/resources/core.js index 2d6b86c..d38360928 100644 --- a/ios/web/web_state/js/resources/core.js +++ b/ios/web/web_state/js/resources/core.js
@@ -547,44 +547,6 @@ return hasFrame_(window, node.target); }; - var getTargetLink_ = function(target) { - var node = target; - // Find the closest ancester that is a link. - while (node) { - if (node instanceof HTMLAnchorElement) - break; - node = node.parentNode; - } - return node; - }; - - var setExternalRequest_ = function(href, target) { - if (typeof(target) == 'undefined' || target == '_blank' || target == '') { - target = '' + Date.now() + '-' + Math.random(); - } - if (typeof(href) == 'undefined') { - // W3C recommended behavior. - href = 'about:blank'; - } - invokeOnHost_({'command': 'externalRequest', - 'href': href, - 'target': target, - 'referrerPolicy': getReferrerPolicy_()}); - }; - - var resetExternalRequest_ = function() { - invokeOnHost_({'command': 'resetExternalRequest'}); - }; - - var clickBubbleListener_ = function(evt) { - if (evt['defaultPrevented']) { - resetExternalRequest_(); - } - // Remove the listener. - evt.currentTarget.removeEventListener( - 'click', clickBubbleListener_, false); - }; - var getComputedWebkitTouchCallout_ = function(element) { return window.getComputedStyle(element, null)['webkitTouchCallout']; }; @@ -594,51 +556,6 @@ __gCrWeb.message.invokeQueues(); } - document.addEventListener('click', function(evt) { - var node = getTargetLink_(evt.target); - - if (!node) - return; - - if (isInternaLink_(node)) { - return; - } - setExternalRequest_(node.href, node.target); - // Add listener to the target and its immediate ancesters. These event - // listeners will be removed if they get called. The listeners for some - // elements might never be removed, but if multiple identical event - // listeners are registered on the same event target with the same - // parameters the duplicate instances are discarded. - for (var level = 0; level < 5; ++level) { - if (node && node != document) { - node.addEventListener('click', clickBubbleListener_, false); - node = node.parentNode; - } else { - break; - } - } - }, true); - - // Intercept clicks on anchors (links) during bubbling phase so that the - // browser can handle target type appropriately. - document.addEventListener('click', function(evt) { - var node = getTargetLink_(evt.target); - - if (!node) - return; - - if (isInternaLink_(node)) { - return; - } else { - // Resets the external request if it has been canceled, otherwise - // updates the href in case it has been changed. - if (evt['defaultPrevented']) - resetExternalRequest_(); - else - setExternalRequest_(node.href, node.target); - } - }, false); - // Capture form submit actions. document.addEventListener('submit', function(evt) { if (evt['defaultPrevented'])
diff --git a/ios/web/web_state/ui/crw_web_controller.h b/ios/web/web_state/ui/crw_web_controller.h index 49165ee..81c11d3 100644 --- a/ios/web/web_state/ui/crw_web_controller.h +++ b/ios/web/web_state/ui/crw_web_controller.h
@@ -29,9 +29,6 @@ PAGE_LOADED = 2 }; -// The accessibility identifier of the top-level container view. -extern NSString* const kContainerViewID; - } // namespace web @class CRWJSInjectionReceiver; @@ -289,7 +286,6 @@ - (NSUInteger)observerCount; - (void)setURLOnStartLoading:(const GURL&)url; - (void)simulateLoadRequestWithURL:(const GURL&)URL; -- (NSString*)externalRequestWindowName; // Returns the header height. - (CGFloat)headerHeight;
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index 04190c9..8eacd96 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -114,37 +114,7 @@ using web::WebState; using web::WebStateImpl; -namespace web { -NSString* const kContainerViewID = @"Container View"; -const char* kWindowNameSeparator = "#"; -NSString* const kUserIsInteractingKey = @"userIsInteracting"; -NSString* const kOriginURLKey = @"originURL"; -NSString* const kLogJavaScript = @"LogJavascript"; - -struct NewWindowInfo { - GURL url; - base::scoped_nsobject<NSString> window_name; - web::ReferrerPolicy referrer_policy; - bool user_is_interacting; - NewWindowInfo(GURL url, - NSString* window_name, - web::ReferrerPolicy referrer_policy, - bool user_is_interacting); - ~NewWindowInfo(); -}; - -NewWindowInfo::NewWindowInfo(GURL target_url, - NSString* target_window_name, - web::ReferrerPolicy target_referrer_policy, - bool target_user_is_interacting) - : url(target_url), - window_name([target_window_name copy]), - referrer_policy(target_referrer_policy), - user_is_interacting(target_user_is_interacting) { -} - -NewWindowInfo::~NewWindowInfo() { -} +namespace { // Struct to capture data about a user interaction. Records the time of the // interaction and the main document URL at that time. @@ -157,20 +127,12 @@ CFAbsoluteTime time; }; -// Values of the UMA |Web.URLVerificationFailure| histogram. -enum WebViewDocumentType { - // Generic contents (e.g. PDF documents). - WEB_VIEW_DOCUMENT_TYPE_GENERIC = 0, - // HTML contents. - WEB_VIEW_DOCUMENT_TYPE_HTML, - // Unknown contents. - WEB_VIEW_DOCUMENT_TYPE_UNKNOWN, - WEB_VIEW_DOCUMENT_TYPE_COUNT, -}; +// Keys for JavaScript command handlers context. +NSString* const kUserIsInteractingKey = @"userIsInteracting"; +NSString* const kOriginURLKey = @"originURL"; -} // namespace web - -namespace { +// Standard User Defaults key for "Log JS" debug setting. +NSString* const kLogJavaScript = @"LogJavascript"; // Key of UMA IOSFix.ViewportZoomBugCount histogram. const char kUMAViewportZoomBugCount[] = "Renderer.ViewportZoomBugCount"; @@ -360,7 +322,7 @@ // Whether a click is in progress. BOOL _clickInProgress; // Data on the recorded last user interaction. - std::unique_ptr<web::UserInteractionEvent> _lastUserInteraction; + std::unique_ptr<UserInteractionEvent> _lastUserInteraction; // YES if there has been user interaction with views owned by this controller. BOOL _userInteractedWithWebController; // The time of the last page transfer start, measured in seconds since Jan 1 @@ -389,7 +351,6 @@ // YES if the web process backing _wkWebView is believed to currently be dead. BOOL _webProcessIsDead; - std::unique_ptr<web::NewWindowInfo> _externalRequest; // Object for loading POST requests with body. base::scoped_nsobject<CRWJSPOSTRequestLoader> _POSTRequestLoader; @@ -570,10 +531,6 @@ // Returns the WKWebViewConfigurationProvider associated with the web // controller's BrowserState. - (web::WKWebViewConfigurationProvider&)webViewConfigurationProvider; -// Returns the type of document object loaded in the web view. -- (web::WebViewDocumentType)webViewDocumentType; -// Converts MIME type string to WebViewDocumentType. -- (web::WebViewDocumentType)documentTypeFromMIMEType:(NSString*)MIMEType; // Extracts Referer value from WKNavigationAction request header. - (NSString*)refererFromNavigationAction:(WKNavigationAction*)action; @@ -809,8 +766,6 @@ // Returns YES if the popup should be blocked, NO otherwise. - (BOOL)shouldBlockPopupWithURL:(const GURL&)popupURL sourceURL:(const GURL&)sourceURL; -// Tries to open a popup with the given new window information. -- (void)openPopupWithInfo:(const web::NewWindowInfo&)windowInfo; // Used in webView:didReceiveAuthenticationChallenge:completionHandler: to // reply with NSURLSessionAuthChallengeDisposition and credentials. @@ -890,9 +845,6 @@ // Handles 'document.submit' message. - (BOOL)handleDocumentSubmitMessage:(base::DictionaryValue*)message context:(NSDictionary*)context; -// Handles 'externalRequest' message. -- (BOOL)handleExternalRequestMessage:(base::DictionaryValue*)message - context:(NSDictionary*)context; // Handles 'form.activity' message. - (BOOL)handleFormActivityMessage:(base::DictionaryValue*)message context:(NSDictionary*)context; @@ -908,9 +860,6 @@ // Handles 'navigator.credentials.notifyFailedSignIn' message. - (BOOL)handleSignInFailedMessage:(base::DictionaryValue*)message context:(NSDictionary*)context; -// Handles 'resetExternalRequest' message. -- (BOOL)handleResetExternalRequestMessage:(base::DictionaryValue*)message - context:(NSDictionary*)context; // Handles 'window.error' message. - (BOOL)handleWindowErrorMessage:(base::DictionaryValue*)message context:(NSDictionary*)context; @@ -1211,7 +1160,12 @@ } - (BOOL)contentIsHTML { - return [self webViewDocumentType] == web::WEB_VIEW_DOCUMENT_TYPE_HTML; + if (!_webView) + return NO; + + std::string MIMEType = self.webState->GetContentsMimeType(); + return MIMEType == "text/html" || MIMEType == "application/xhtml+xml" || + MIMEType == "application/xml"; } // Stop doing stuff, especially network stuff. Close the request tracker. @@ -2034,18 +1988,19 @@ _containerView.reset( [[CRWWebControllerContainerView alloc] initWithDelegate:self]); - // Compute and set the frame of the containerView. + // This will be resized later, but matching the final frame will minimize + // re-rendering. Use the screen size because the application's key window + // may still be nil. + // TODO(crbug.com/688259): Stop subtracting status bar height. CGFloat statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height; - CGRect containerViewFrame = - [UIApplication sharedApplication].keyWindow.bounds; + CGRect containerViewFrame = [UIScreen mainScreen].bounds; containerViewFrame.origin.y += statusBarHeight; containerViewFrame.size.height -= statusBarHeight; _containerView.get().frame = containerViewFrame; DCHECK(!CGRectIsEmpty(_containerView.get().frame)); [_containerView addGestureRecognizer:[self touchTrackingRecognizer]]; - [_containerView setAccessibilityIdentifier:web::kContainerViewID]; // Is |currentUrl| a web scheme or native chrome scheme. web::NavigationItem* item = [self currentNavItem]; const GURL currentNavigationURL = @@ -2512,10 +2467,10 @@ DCHECK(handlerImplementation); NSMutableDictionary* context = [NSMutableDictionary dictionaryWithObject:@(userIsInteracting) - forKey:web::kUserIsInteractingKey]; + forKey:kUserIsInteractingKey]; NSURL* originNSURL = net::NSURLWithGURL(originURL); if (originNSURL) - context[web::kOriginURLKey] = originNSURL; + context[kOriginURLKey] = originNSURL; return handlerImplementation(self, handler, message, context); } @@ -2534,8 +2489,6 @@ @selector(handleDocumentFaviconsMessage:context:); (*handlers)["document.submit"] = @selector(handleDocumentSubmitMessage:context:); - (*handlers)["externalRequest"] = - @selector(handleExternalRequestMessage:context:); (*handlers)["form.activity"] = @selector(handleFormActivityMessage:context:); (*handlers)["navigator.credentials.request"] = @@ -2546,8 +2499,6 @@ @selector(handleSignedOutMessage:context:); (*handlers)["navigator.credentials.notifyFailedSignIn"] = @selector(handleSignInFailedMessage:context:); - (*handlers)["resetExternalRequest"] = - @selector(handleResetExternalRequestMessage:context:); (*handlers)["window.error"] = @selector(handleWindowErrorMessage:context:); (*handlers)["window.hashchange"] = @selector(handleWindowHashChangeMessage:context:); @@ -2644,8 +2595,7 @@ return NO; } _webStateImpl->OnScriptCommandReceived( - messageContent, *message, currentURL, - context[web::kUserIsInteractingKey]); + messageContent, *message, currentURL, context[kUserIsInteractingKey]); _webStateImpl->ProcessWebUIMessage(currentURL, messageContent, *arguments); return YES; @@ -2660,7 +2610,7 @@ - (BOOL)handleConsoleMessage:(base::DictionaryValue*)message context:(NSDictionary*)context { // Do not log if JS logging is off. - if (![[NSUserDefaults standardUserDefaults] boolForKey:web::kLogJavaScript]) { + if (![[NSUserDefaults standardUserDefaults] boolForKey:kLogJavaScript]) { return YES; } @@ -2749,45 +2699,12 @@ // We decide the form is user-submitted if the user has interacted with // the main page (using logic from the popup blocker), or if the keyboard // is visible. - BOOL submittedByUser = [context[web::kUserIsInteractingKey] boolValue] || + BOOL submittedByUser = [context[kUserIsInteractingKey] boolValue] || [_webViewProxy keyboardAccessory]; _webStateImpl->OnDocumentSubmitted(formName, submittedByUser); return YES; } -- (BOOL)handleExternalRequestMessage:(base::DictionaryValue*)message - context:(NSDictionary*)context { - std::string href; - std::string target; - std::string referrerPolicy; - if (!message->GetString("href", &href)) { - DLOG(WARNING) << "JS message parameter not found: href"; - return NO; - } - if (!message->GetString("target", &target)) { - DLOG(WARNING) << "JS message parameter not found: target"; - return NO; - } - if (!message->GetString("referrerPolicy", &referrerPolicy)) { - DLOG(WARNING) << "JS message parameter not found: referrerPolicy"; - return NO; - } - // Round-trip the href through NSURL; this URL will be compared as a - // string against a UIWebView-provided NSURL later, and must match exactly - // for the new window to trigger, so the escaping needs to be NSURL-style. - // TODO(stuartmorgan): Comparing against a URL whose exact formatting we - // don't control is fundamentally fragile; try to find another - // way of handling this. - DCHECK(context[web::kUserIsInteractingKey]); - NSString* windowName = - base::SysUTF8ToNSString(href + web::kWindowNameSeparator + target); - _externalRequest.reset(new web::NewWindowInfo( - net::GURLWithNSURL(net::NSURLWithGURL(GURL(href))), windowName, - web::ReferrerPolicyFromString(referrerPolicy), - [context[web::kUserIsInteractingKey] boolValue])); - return YES; -} - - (BOOL)handleFormActivityMessage:(base::DictionaryValue*)message context:(NSDictionary*)context { std::string formName; @@ -2833,11 +2750,10 @@ } federations.push_back(federation); } - DCHECK(context[web::kUserIsInteractingKey]); + DCHECK(context[kUserIsInteractingKey]); _webStateImpl->OnCredentialsRequested( - static_cast<int>(request_id), - net::GURLWithNSURL(context[web::kOriginURLKey]), unmediated, federations, - [context[web::kUserIsInteractingKey] boolValue]); + static_cast<int>(request_id), net::GURLWithNSURL(context[kOriginURLKey]), + unmediated, federations, [context[kUserIsInteractingKey] boolValue]); return YES; } @@ -2856,11 +2772,11 @@ return NO; } _webStateImpl->OnSignedIn(static_cast<int>(request_id), - net::GURLWithNSURL(context[web::kOriginURLKey]), + net::GURLWithNSURL(context[kOriginURLKey]), credential); } else { _webStateImpl->OnSignedIn(static_cast<int>(request_id), - net::GURLWithNSURL(context[web::kOriginURLKey])); + net::GURLWithNSURL(context[kOriginURLKey])); } return YES; } @@ -2873,7 +2789,7 @@ return NO; } _webStateImpl->OnSignedOut(static_cast<int>(request_id), - net::GURLWithNSURL(context[web::kOriginURLKey])); + net::GURLWithNSURL(context[kOriginURLKey])); return YES; } @@ -2891,23 +2807,16 @@ DLOG(WARNING) << "JS message parameter 'credential' is invalid"; return NO; } - _webStateImpl->OnSignInFailed( - static_cast<int>(request_id), - net::GURLWithNSURL(context[web::kOriginURLKey]), credential); + _webStateImpl->OnSignInFailed(static_cast<int>(request_id), + net::GURLWithNSURL(context[kOriginURLKey]), + credential); } else { - _webStateImpl->OnSignInFailed( - static_cast<int>(request_id), - net::GURLWithNSURL(context[web::kOriginURLKey])); + _webStateImpl->OnSignInFailed(static_cast<int>(request_id), + net::GURLWithNSURL(context[kOriginURLKey])); } return YES; } -- (BOOL)handleResetExternalRequestMessage:(base::DictionaryValue*)message - context:(NSDictionary*)context { - _externalRequest.reset(); - return YES; -} - - (BOOL)handleWindowErrorMessage:(base::DictionaryValue*)message context:(NSDictionary*)context { std::string errorMessage; @@ -3245,26 +3154,6 @@ BOOL isNavigationTypeLinkActivated = action.navigationType == WKNavigationTypeLinkActivated; - // Check if the request should be delayed. - if (_externalRequest && _externalRequest->url == requestURL) { - // Links that can't be shown in a tab by Chrome but can be handled by - // external apps (e.g. tel:, mailto:) are opened directly despite the target - // attribute on the link. We don't open a new tab for them because Mobile - // Safari doesn't do that (and sites are expecting us to do the same) and - // also because there would be nothing shown in that new tab; it would - // remain on about:blank (see crbug.com/240178) - if ([CRWWebController webControllerCanShow:requestURL] || - ![_delegate openExternalURL:requestURL - linkClicked:isNavigationTypeLinkActivated]) { - web::NewWindowInfo windowInfo = *_externalRequest; - dispatch_async(dispatch_get_main_queue(), ^{ - [self openPopupWithInfo:windowInfo]; - }); - } - _externalRequest.reset(); - return NO; - } - // Check if the link navigation leads to a launch of an external app. // TODO(crbug.com/607780): Revise the logic of allowing external app launch // and move it to externalAppLauncher. @@ -3510,33 +3399,6 @@ sourceURL:sourceURL]; } -- (void)openPopupWithInfo:(const web::NewWindowInfo&)windowInfo { - const GURL url(windowInfo.url); - web::NavigationItem* item = [self currentNavItem]; - const GURL currentURL = item ? item->GetVirtualURL() : GURL::EmptyGURL(); - NSString* windowName = windowInfo.window_name.get(); - web::Referrer referrer(currentURL, windowInfo.referrer_policy); - base::WeakNSObject<CRWWebController> weakSelf(self); - void (^showPopupHandler)() = ^{ - CRWWebController* child = [[weakSelf delegate] webPageOrderedOpen:url - referrer:referrer - windowName:windowName - inBackground:NO]; - DCHECK(!child || child.sessionController.openedByDOM); - }; - - BOOL showPopup = windowInfo.user_is_interacting || - (![self shouldBlockPopupWithURL:url sourceURL:currentURL]); - if (showPopup) { - showPopupHandler(); - } else if ([_delegate - respondsToSelector:@selector(webController:didBlockPopup:)]) { - web::BlockedPopupInfo blockedPopupInfo(url, referrer, windowName, - showPopupHandler); - [_delegate webController:self didBlockPopup:blockedPopupInfo]; - } -} - #pragma mark - #pragma mark Auth Challenge @@ -3659,7 +3521,7 @@ navigationManager.GetItemCount() ? navigationManager.GetLastCommittedItem()->GetURL() : [self currentURL]; - _lastUserInteraction.reset(new web::UserInteractionEvent(mainDocumentURL)); + _lastUserInteraction.reset(new UserInteractionEvent(mainDocumentURL)); } } @@ -4472,16 +4334,6 @@ return web::WKWebViewConfigurationProvider::FromBrowserState(browserState); } -- (web::WebViewDocumentType)webViewDocumentType { - // This happens during tests. - if (!_webView) { - return web::WEB_VIEW_DOCUMENT_TYPE_GENERIC; - } - - std::string MIMEType = self.webState->GetContentsMimeType(); - return [self documentTypeFromMIMEType:base::SysUTF8ToNSString(MIMEType)]; -} - - (void)loadRequest:(NSMutableURLRequest*)request { [_navigationStates setState:web::WKNavigationState::REQUESTED forNavigation:[_webView loadRequest:request]]; @@ -5434,26 +5286,6 @@ _loadPhase = web::LOAD_REQUESTED; } -- (NSString*)externalRequestWindowName { - if (!_externalRequest || !_externalRequest->window_name) - return @""; - return _externalRequest->window_name; -} - -- (web::WebViewDocumentType)documentTypeFromMIMEType:(NSString*)MIMEType { - if (!MIMEType.length) { - return web::WEB_VIEW_DOCUMENT_TYPE_UNKNOWN; - } - - if ([MIMEType isEqualToString:@"text/html"] || - [MIMEType isEqualToString:@"application/xhtml+xml"] || - [MIMEType isEqualToString:@"application/xml"]) { - return web::WEB_VIEW_DOCUMENT_TYPE_HTML; - } - - return web::WEB_VIEW_DOCUMENT_TYPE_GENERIC; -} - - (NSString*)refererFromNavigationAction:(WKNavigationAction*)action { return [action.request valueForHTTPHeaderField:@"Referer"]; }
diff --git a/ios/web/web_thread_impl.cc b/ios/web/web_thread_impl.cc index 2a28556b..eaab3d9 100644 --- a/ios/web/web_thread_impl.cc +++ b/ios/web/web_thread_impl.cc
@@ -5,6 +5,7 @@ #include "ios/web/web_thread_impl.h" #include <string> +#include <utility> #include "base/atomicops.h" #include "base/bind.h" @@ -335,10 +336,10 @@ // static bool WebThread::PostBlockingPoolTaskAndReply( const tracked_objects::Location& from_here, - const base::Closure& task, - const base::Closure& reply) { - return g_globals.Get().blocking_pool->PostTaskAndReply(from_here, task, - reply); + base::Closure task, + base::Closure reply) { + return g_globals.Get().blocking_pool->PostTaskAndReply( + from_here, std::move(task), std::move(reply)); } // static @@ -440,10 +441,10 @@ // static bool WebThread::PostTaskAndReply(ID identifier, const tracked_objects::Location& from_here, - const base::Closure& task, - const base::Closure& reply) { + base::Closure task, + base::Closure reply) { return GetTaskRunnerForThread(identifier) - ->PostTaskAndReply(from_here, task, reply); + ->PostTaskAndReply(from_here, std::move(task), std::move(reply)); } // static
diff --git a/ios/web_view/OWNERS b/ios/web_view/OWNERS index 7ec8b42..86b60740 100644 --- a/ios/web_view/OWNERS +++ b/ios/web_view/OWNERS
@@ -1,4 +1,5 @@ eugenebut@chromium.org +michaeldo@chromium.org rohitrao@chromium.org # These are for the common case of adding or renaming files. If you're doing
diff --git a/ios/web_view/internal/criwv_web_view.mm b/ios/web_view/internal/criwv_web_view.mm index 5982379..1fa2839 100644 --- a/ios/web_view/internal/criwv_web_view.mm +++ b/ios/web_view/internal/criwv_web_view.mm
@@ -114,9 +114,14 @@ _webState->Stop(); } -- (void)loadURL:(NSURL*)URL { - web::NavigationManager::WebLoadParams params(net::GURLWithNSURL(URL)); +- (void)loadRequest:(NSURLRequest*)request { + DCHECK_EQ(nil, request.HTTPBodyStream) + << "request.HTTPBodyStream is not supported."; + + web::NavigationManager::WebLoadParams params(net::GURLWithNSURL(request.URL)); params.transition_type = ui::PAGE_TRANSITION_TYPED; + params.extra_headers.reset([request.allHTTPHeaderFields copy]); + params.post_data.reset([request.HTTPBody copy]); _webState->GetNavigationManager()->LoadURLWithParams(params); }
diff --git a/ios/web_view/public/criwv_web_view.h b/ios/web_view/public/criwv_web_view.h index 1bc5697..9ead24c 100644 --- a/ios/web_view/public/criwv_web_view.h +++ b/ios/web_view/public/criwv_web_view.h
@@ -54,8 +54,9 @@ // Stops loading the current page. - (void)stopLoading; -// Loads the given |url| in this web view. -- (void)loadURL:(NSURL*)url; +// Loads the given URL request in this web view. +// Unlike WKWebView, this method supports HTTPBody. +- (void)loadRequest:(NSURLRequest*)request; // Evaluates a JavaScript string. // The completion handler is invoked when script evaluation completes.
diff --git a/ios/web_view/shell/shell_view_controller.m b/ios/web_view/shell/shell_view_controller.m index 5d7837a..60c0bba 100644 --- a/ios/web_view/shell/shell_view_controller.m +++ b/ios/web_view/shell/shell_view_controller.m
@@ -126,7 +126,9 @@ UIViewAutoresizingFlexibleHeight]; [_containerView addSubview:_webView]; - [_webView loadURL:[NSURL URLWithString:@"https://www.google.com/"]]; + NSURLRequest* request = [NSURLRequest + requestWithURL:[NSURL URLWithString:@"https://www.google.com/"]]; + [_webView loadRequest:request]; } - (UIBarPosition)positionForBar:(id<UIBarPositioning>)bar { @@ -153,7 +155,9 @@ } - (BOOL)textFieldShouldReturn:(UITextField*)field { - [_webView loadURL:[NSURL URLWithString:[field text]]]; + NSURLRequest* request = + [NSURLRequest requestWithURL:[NSURL URLWithString:[field text]]]; + [_webView loadRequest:request]; [field resignFirstResponder]; [self updateToolbar]; return YES;
diff --git a/media/OWNERS b/media/OWNERS index 8a329a4c..683ae0d 100644 --- a/media/OWNERS +++ b/media/OWNERS
@@ -15,6 +15,7 @@ jrummell@chromium.org liberato@chromium.org sandersd@chromium.org +tguilbert@chromium.org watk@chromium.org wolenetz@chromium.org xhwang@chromium.org
diff --git a/media/mojo/services/mojo_video_decoder_service.h b/media/mojo/services/mojo_video_decoder_service.h index ce824eee..cc65e05 100644 --- a/media/mojo/services/mojo_video_decoder_service.h +++ b/media/mojo/services/mojo_video_decoder_service.h
@@ -14,6 +14,7 @@ namespace media { +class DecoderBuffer; class MojoDecoderBufferReader; class MojoMediaClient; class VideoDecoder;
diff --git a/media/renderers/video_overlay_factory.cc b/media/renderers/video_overlay_factory.cc index de0331a..6bb1f0f 100644 --- a/media/renderers/video_overlay_factory.cc +++ b/media/renderers/video_overlay_factory.cc
@@ -25,8 +25,13 @@ gpu_factories_->GetGLContextLock()); if (lock) { gpu::gles2::GLES2Interface* gl = lock->ContextGL(); - image_id_ = gl->CreateGpuMemoryBufferImageCHROMIUM( - 1, 1, GL_RGBA, GL_READ_WRITE_CHROMIUM); + gpu_memory_buffer_ = gpu_factories_->CreateGpuMemoryBuffer( + gfx::Size(1, 1), gfx::BufferFormat::RGBA_8888, + gfx::BufferUsage::SCANOUT); + if (gpu_memory_buffer_) { + image_id_ = gl->CreateImageCHROMIUM( + gpu_memory_buffer_->AsClientBuffer(), 1, 1, GL_RGBA); + } if (image_id_) { gl->GenTextures(1, &texture_id_); gl->BindTexture(GL_TEXTURE_2D, texture_id_); @@ -65,6 +70,7 @@ friend class VideoOverlayFactory; GpuVideoAcceleratorFactories* gpu_factories_; + std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer_; GLuint image_id_; GLuint texture_id_; gpu::Mailbox mailbox_;
diff --git a/mojo/android/javatests/init_library.cc b/mojo/android/javatests/init_library.cc index 96752401..9e1a593 100644 --- a/mojo/android/javatests/init_library.cc +++ b/mojo/android/javatests/init_library.cc
@@ -6,6 +6,7 @@ #include "base/android/base_jni_registrar.h" #include "base/android/jni_android.h" #include "base/android/jni_registrar.h" +#include "base/android/library_loader/library_loader_hooks.h" #include "base/bind.h" #include "mojo/android/javatests/mojo_test_case.h" #include "mojo/android/javatests/validation_test_util.h" @@ -24,11 +25,14 @@ bool RegisterJNI(JNIEnv* env) { return base::android::RegisterJni(env) && - RegisterNativeMethods(env, kMojoRegisteredMethods, - arraysize(kMojoRegisteredMethods)); + RegisterNativeMethods(env, kMojoRegisteredMethods, + arraysize(kMojoRegisteredMethods)); } -bool Init() { +bool NativeInit() { + if (!base::android::OnJNIOnLoadInit()) + return false; + mojo::edk::Init(); return true; } @@ -36,13 +40,11 @@ } // namespace JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { - std::vector<base::android::RegisterCallback> register_callbacks; - register_callbacks.push_back(base::Bind(&RegisterJNI)); - std::vector<base::android::InitCallback> init_callbacks; - init_callbacks.push_back(base::Bind(&Init)); - if (!base::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks) || - !base::android::OnJNIOnLoadInit(init_callbacks)) + base::android::InitVM(vm); + JNIEnv* env = base::android::AttachCurrentThread(); + if (!base::android::OnJNIOnLoadRegisterJNI(env) || !RegisterJNI(env) || + !NativeInit()) { return -1; - + } return JNI_VERSION_1_4; }
diff --git a/mojo/common/BUILD.gn b/mojo/common/BUILD.gn index e0f18ad..9e74e582 100644 --- a/mojo/common/BUILD.gn +++ b/mojo/common/BUILD.gn
@@ -77,16 +77,6 @@ ] } -test("mojo_common_perftests") { - deps = [ - ":common", - "//base", - "//mojo/edk/test:run_all_perftests", - "//mojo/public/cpp/test_support:test_utils", - "//testing/gtest", - ] -} - source_set("struct_traits") { sources = [ "common_custom_types_struct_traits.cc",
diff --git a/mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h b/mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h index edbf27b..014ff8bd 100644 --- a/mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h +++ b/mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h
@@ -22,7 +22,7 @@ WTF::Vector<T> result; result.reserveCapacity(input.size()); for (const auto& element : input) - result.append(internal::Clone(element)); + result.push_back(internal::Clone(element)); return result; }
diff --git a/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc b/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc index 5551e45..039308b5 100644 --- a/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc +++ b/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc
@@ -14,6 +14,7 @@ #include "mojo/public/interfaces/bindings/tests/test_wtf_types.mojom-blink.h" #include "mojo/public/interfaces/bindings/tests/test_wtf_types.mojom.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/Source/wtf/text/StringHash.h" namespace mojo { namespace test {
diff --git a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py index e66bec3..c75013b 100644 --- a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py +++ b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
@@ -191,10 +191,8 @@ return False return all(Check(field.kind) for field in kind.fields) elif mojom.IsEnumKind(kind): - if (IsTypemappedKind(kind) and - not _current_typemap[GetFullMojomNameForKind(kind)]["hashable"]): - return False - return True + return not IsTypemappedKind(kind) or _current_typemap[ + GetFullMojomNameForKind(kind)]["hashable"] elif mojom.IsUnionKind(kind): return all(Check(field.kind) for field in kind.fields) elif mojom.IsAnyHandleKind(kind): @@ -419,8 +417,7 @@ def TranslateConstants(token, kind): if isinstance(token, mojom.NamedValue): - return _NameFormatter(token, _variant).FormatForCpp( - flatten_nested_kind=True) + return GetNameForKind(token, flatten_nested_kind=True) if isinstance(token, mojom.BuiltinValue): if token.value == "double.INFINITY": @@ -575,7 +572,6 @@ "is_typemapped_kind": IsTypemappedKind, "is_union_kind": mojom.IsUnionKind, "passes_associated_kinds": mojom.PassesAssociatedKinds, - "struct_size": lambda ps: ps.GetTotalSize() + _HEADER_SIZE, "stylize_method": generator.StudlyCapsToCamel, "under_to_camel": generator.UnderToCamel, "unmapped_type_for_serializer": GetUnmappedTypeForSerializer, @@ -583,15 +579,81 @@ def GetExtraTraitsHeaders(self): extra_headers = set() - for entry in self.typemap.itervalues(): - extra_headers.update(entry.get("traits_headers", [])) - return list(extra_headers) + for typemap in self._GetAllUsedTypemaps(): + extra_headers.update(typemap.get("traits_headers", [])) + return sorted(extra_headers) + + def _GetAllUsedTypemaps(self): + """Returns the typemaps for types needed for serialization in this module. + + A type is needed for serialization if it is contained by a struct or union + defined in this module, is a parameter of a message in an interface in + this module or is contained within another type needed for serialization. + """ + used_typemaps = [] + seen_types = set() + def AddKind(kind): + if (mojom.IsIntegralKind(kind) or mojom.IsStringKind(kind) or + mojom.IsDoubleKind(kind) or mojom.IsFloatKind(kind) or + mojom.IsAnyHandleKind(kind) or + mojom.IsInterfaceKind(kind) or + mojom.IsInterfaceRequestKind(kind) or + mojom.IsAssociatedKind(kind)): + pass + elif mojom.IsArrayKind(kind): + AddKind(kind.kind) + elif mojom.IsMapKind(kind): + AddKind(kind.key_kind) + AddKind(kind.value_kind) + else: + name = GetFullMojomNameForKind(kind) + if name in seen_types: + return + seen_types.add(name) + + typemap = _current_typemap.get(name, None) + if typemap: + used_typemaps.append(typemap) + if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind): + for field in kind.fields: + AddKind(field.kind) + + for kind in self.module.structs + self.module.unions: + for field in kind.fields: + AddKind(field.kind) + + for interface in self.module.interfaces: + for method in interface.methods: + for parameter in method.parameters + (method.response_parameters or []): + AddKind(parameter.kind) + + return used_typemaps def GetExtraPublicHeaders(self): - extra_headers = set() - for entry in self.typemap.itervalues(): - extra_headers.update(entry.get("public_headers", [])) - return list(extra_headers) + all_enums = list(self.module.enums) + for struct in self.module.structs: + all_enums.extend(struct.enums) + for interface in self.module.interfaces: + all_enums.extend(interface.enums) + + types = set(GetFullMojomNameForKind(typename) + for typename in + self.module.structs + all_enums + self.module.unions) + headers = set() + for typename, typemap in self.typemap.iteritems(): + if typename in types: + headers.update(typemap.get("public_headers", [])) + return sorted(headers) + + def _GetDirectlyUsedKinds(self): + for struct in self.module.structs + self.module.unions: + for field in struct.fields: + yield field.kind + + for interface in self.module.interfaces: + for method in interface.methods: + for param in method.parameters + (method.response_parameters or []): + yield param.kind def GetJinjaExports(self): structs = self.GetStructs()
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/module.py b/mojo/public/tools/bindings/pylib/mojom/generate/module.py index b763f02..df9c2c5 100644 --- a/mojo/public/tools/bindings/pylib/mojom/generate/module.py +++ b/mojo/public/tools/bindings/pylib/mojom/generate/module.py
@@ -690,6 +690,10 @@ return kind.spec == FLOAT.spec +def IsDoubleKind(kind): + return kind.spec == DOUBLE.spec + + def IsIntegralKind(kind): return (kind.spec == BOOL.spec or kind.spec == INT8.spec or
diff --git a/net/base/filename_util_icu.cc b/net/base/filename_util_icu.cc index 7436a81..9460cd4 100644 --- a/net/base/filename_util_icu.cc +++ b/net/base/filename_util_icu.cc
@@ -4,7 +4,6 @@ #include "net/base/filename_util.h" -#include "base/bind.h" #include "base/files/file_path.h" #include "base/i18n/file_util_icu.h" #include "base/strings/string16.h" @@ -50,14 +49,9 @@ const std::string& suggested_name, const std::string& mime_type, const std::string& default_name) { - return GetSuggestedFilenameImpl( - url, - content_disposition, - referrer_charset, - suggested_name, - mime_type, - default_name, - base::Bind(&base::i18n::ReplaceIllegalCharactersInPath)); + return GetSuggestedFilenameImpl(url, content_disposition, referrer_charset, + suggested_name, mime_type, default_name, + &base::i18n::ReplaceIllegalCharactersInPath); } base::FilePath GenerateFileName(const GURL& url, @@ -67,13 +61,8 @@ const std::string& mime_type, const std::string& default_file_name) { base::FilePath generated_name(GenerateFileNameImpl( - url, - content_disposition, - referrer_charset, - suggested_name, - mime_type, - default_file_name, - base::Bind(&base::i18n::ReplaceIllegalCharactersInPath))); + url, content_disposition, referrer_charset, suggested_name, mime_type, + default_file_name, &base::i18n::ReplaceIllegalCharactersInPath)); #if defined(OS_CHROMEOS) // When doing file manager operations on ChromeOS, the file paths get
diff --git a/net/base/filename_util_internal.cc b/net/base/filename_util_internal.cc index fa0a91f..fa81d18 100644 --- a/net/base/filename_util_internal.cc +++ b/net/base/filename_util_internal.cc
@@ -221,7 +221,7 @@ const std::string& suggested_name, const std::string& mime_type, const std::string& default_name, - ReplaceIllegalCharactersCallback replace_illegal_characters_callback) { + ReplaceIllegalCharactersFunction replace_illegal_characters_function) { // TODO: this function to be updated to match the httpbis recommendations. // Talk to abarth for the latest news. @@ -277,7 +277,7 @@ : base::FilePath::StringType(kFinalFallbackName); overwrite_extension = false; } - replace_illegal_characters_callback.Run(&result_str, '-'); + replace_illegal_characters_function(&result_str, '-'); base::FilePath result(result_str); // extension should not appended to filename derived from // content-disposition, if it does not have one. @@ -305,15 +305,10 @@ const std::string& suggested_name, const std::string& mime_type, const std::string& default_file_name, - ReplaceIllegalCharactersCallback replace_illegal_characters_callback) { - base::string16 file_name = - GetSuggestedFilenameImpl(url, - content_disposition, - referrer_charset, - suggested_name, - mime_type, - default_file_name, - replace_illegal_characters_callback); + ReplaceIllegalCharactersFunction replace_illegal_characters_function) { + base::string16 file_name = GetSuggestedFilenameImpl( + url, content_disposition, referrer_charset, suggested_name, mime_type, + default_file_name, replace_illegal_characters_function); #if defined(OS_WIN) base::FilePath generated_name(file_name);
diff --git a/net/base/filename_util_internal.h b/net/base/filename_util_internal.h index c1a73bb..3b9f0e2 100644 --- a/net/base/filename_util_internal.h +++ b/net/base/filename_util_internal.h
@@ -9,7 +9,6 @@ #include <string> -#include "base/callback.h" #include "base/files/file_path.h" #include "base/strings/string16.h" @@ -17,9 +16,8 @@ namespace net { -typedef base::Callback< - void(base::FilePath::StringType* file_name, char replace_char)> - ReplaceIllegalCharactersCallback; +using ReplaceIllegalCharactersFunction = + void (*)(base::FilePath::StringType* file_name, char replace_char); void SanitizeGeneratedFileName(base::FilePath::StringType* filename, bool replace_trailing); @@ -32,7 +30,7 @@ bool FilePathToString16(const base::FilePath& path, base::string16* converted); -// Similar to GetSuggestedFilename(), but takes callback to replace illegal +// Similar to GetSuggestedFilename(), but takes a function to replace illegal // characters. base::string16 GetSuggestedFilenameImpl( const GURL& url, @@ -41,9 +39,9 @@ const std::string& suggested_name, const std::string& mime_type, const std::string& default_name, - ReplaceIllegalCharactersCallback replace_illegal_characters_callback); + ReplaceIllegalCharactersFunction replace_illegal_characters_function); -// Similar to GenerateFileName(), but takes callback to replace illegal +// Similar to GenerateFileName(), but takes a function to replace illegal // characters. base::FilePath GenerateFileNameImpl( const GURL& url, @@ -52,7 +50,7 @@ const std::string& suggested_name, const std::string& mime_type, const std::string& default_name, - ReplaceIllegalCharactersCallback replace_illegal_characters_callback); + ReplaceIllegalCharactersFunction replace_illegal_characters_function); } // namespace net
diff --git a/net/cert_net/cert_net_fetcher_impl_unittest.cc b/net/cert_net/cert_net_fetcher_impl_unittest.cc index 99f5770..067e6fe 100644 --- a/net/cert_net/cert_net_fetcher_impl_unittest.cc +++ b/net/cert_net/cert_net_fetcher_impl_unittest.cc
@@ -69,7 +69,7 @@ base::MakeUnique<HttpNetworkSession>(params)); storage_.set_http_transaction_factory(base::MakeUnique<HttpCache>( storage_.http_network_session(), HttpCache::DefaultBackend::InMemory(0), - false /* set_up_quic_server_info */)); + false /* is_main_cache */)); storage_.set_job_factory(base::MakeUnique<URLRequestJobFactoryImpl>()); }
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc index b02ddf0..39b86328 100644 --- a/net/http/http_cache.cc +++ b/net/http/http_cache.cc
@@ -295,14 +295,14 @@ //----------------------------------------------------------------------------- HttpCache::HttpCache(HttpNetworkSession* session, std::unique_ptr<BackendFactory> backend_factory, - bool set_up_quic_server_info) + bool is_main_cache) : HttpCache(base::MakeUnique<HttpNetworkLayer>(session), std::move(backend_factory), - set_up_quic_server_info) {} + is_main_cache) {} HttpCache::HttpCache(std::unique_ptr<HttpTransactionFactory> network_layer, std::unique_ptr<BackendFactory> backend_factory, - bool set_up_quic_server_info) + bool is_main_cache) : net_log_(nullptr), backend_factory_(std::move(backend_factory)), building_backend_(false), @@ -318,7 +318,7 @@ // rather than having logic only used in unit tests here. if (session) { net_log_ = session->net_log(); - if (set_up_quic_server_info && + if (is_main_cache && !session->quic_stream_factory()->has_quic_server_info_factory()) { // QuicStreamFactory takes ownership of QuicServerInfoFactoryAdaptor. session->quic_stream_factory()->set_quic_server_info_factory(
diff --git a/net/http/http_cache.h b/net/http/http_cache.h index 2aae2fc..f881b2a05 100644 --- a/net/http/http_cache.h +++ b/net/http/http_cache.h
@@ -123,17 +123,18 @@ // // The HttpCache must be destroyed before the HttpNetworkSession. // - // If |set_up_quic_server_info| is true, configures the cache to track + // If |is_main_cache| is true, configures the cache to track // information about servers supporting QUIC. + // TODO(zhongyi): remove |is_main_cache| when we get rid of cache split. HttpCache(HttpNetworkSession* session, std::unique_ptr<BackendFactory> backend_factory, - bool set_up_quic_server_info); + bool is_main_cache); // Initialize the cache from its component parts. |network_layer| and // |backend_factory| will be destroyed when the HttpCache is. HttpCache(std::unique_ptr<HttpTransactionFactory> network_layer, std::unique_ptr<BackendFactory> backend_factory, - bool set_up_quic_server_info); + bool is_main_cache); ~HttpCache() override;
diff --git a/net/http/mock_http_cache.cc b/net/http/mock_http_cache.cc index d7c08bac..205a45e 100644 --- a/net/http/mock_http_cache.cc +++ b/net/http/mock_http_cache.cc
@@ -546,16 +546,15 @@ std::unique_ptr<HttpCache::BackendFactory> disk_cache_factory) : MockHttpCache(std::move(disk_cache_factory), false) {} -MockHttpCache::MockHttpCache(bool set_up_quic_server_info) - : MockHttpCache(base::MakeUnique<MockBackendFactory>(), - set_up_quic_server_info) {} +MockHttpCache::MockHttpCache(bool is_main_cache) + : MockHttpCache(base::MakeUnique<MockBackendFactory>(), is_main_cache) {} MockHttpCache::MockHttpCache( std::unique_ptr<HttpCache::BackendFactory> disk_cache_factory, - bool set_up_quic_server_info) + bool is_main_cache) : http_cache_(base::MakeUnique<MockNetworkLayer>(), std::move(disk_cache_factory), - set_up_quic_server_info) {} + is_main_cache) {} disk_cache::Backend* MockHttpCache::backend() { TestCompletionCallback cb;
diff --git a/net/http/mock_http_cache.h b/net/http/mock_http_cache.h index c6612c4..c920387 100644 --- a/net/http/mock_http_cache.h +++ b/net/http/mock_http_cache.h
@@ -182,11 +182,11 @@ MockHttpCache(); explicit MockHttpCache( std::unique_ptr<HttpCache::BackendFactory> disk_cache_factory); - // |set_up_quic_server_info| if set, will set a quic server info factory. - explicit MockHttpCache(bool set_up_quic_server_info); + // |is_main_cache| if set, will set a quic server info factory. + explicit MockHttpCache(bool is_main_cache); MockHttpCache(std::unique_ptr<HttpCache::BackendFactory> disk_cache_factory, - bool set_up_quic_server_info); + bool is_main_cache); HttpCache* http_cache() { return &http_cache_; }
diff --git a/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc b/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc index c6a4efd..afcee7f9 100644 --- a/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc +++ b/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc
@@ -352,7 +352,7 @@ }; BidirectionalStreamQuicImplTest() - : crypto_config_(CryptoTestUtils::ProofVerifierForTesting()), + : crypto_config_(crypto_test_utils::ProofVerifierForTesting()), read_buffer_(new IOBufferWithSize(4096)), connection_id_(2), stream_id_(kClientDataStreamId1),
diff --git a/net/quic/chromium/crypto/proof_source_chromium.cc b/net/quic/chromium/crypto/proof_source_chromium.cc index dd8ce1f8..fb14ba0 100644 --- a/net/quic/chromium/crypto/proof_source_chromium.cc +++ b/net/quic/chromium/crypto/proof_source_chromium.cc
@@ -76,7 +76,7 @@ return true; } -bool ProofSourceChromium::GetProof( +bool ProofSourceChromium::GetProofInner( const QuicSocketAddress& server_addr, const string& hostname, const string& server_config, @@ -146,8 +146,10 @@ string signature; string leaf_cert_sct; QuicCryptoProof out_proof; - const bool ok = GetProof(server_addr, hostname, server_config, quic_version, - chlo_hash, connection_options, &chain, &out_proof); + + const bool ok = + GetProofInner(server_addr, hostname, server_config, quic_version, + chlo_hash, connection_options, &chain, &out_proof); callback->Run(ok, chain, out_proof, nullptr /* details */); }
diff --git a/net/quic/chromium/crypto/proof_source_chromium.h b/net/quic/chromium/crypto/proof_source_chromium.h index 95b892d..f0a8c30 100644 --- a/net/quic/chromium/crypto/proof_source_chromium.h +++ b/net/quic/chromium/crypto/proof_source_chromium.h
@@ -33,15 +33,6 @@ const base::FilePath& sct_path); // ProofSource interface - bool GetProof(const QuicSocketAddress& server_ip, - const std::string& hostname, - const std::string& server_config, - QuicVersion quic_version, - base::StringPiece chlo_hash, - const QuicTagVector& connection_options, - QuicReferenceCountedPointer<ProofSource::Chain>* out_chain, - QuicCryptoProof* proof) override; - void GetProof(const QuicSocketAddress& server_ip, const std::string& hostname, const std::string& server_config, @@ -51,6 +42,15 @@ std::unique_ptr<Callback> callback) override; private: + bool GetProofInner(const QuicSocketAddress& server_ip, + const std::string& hostname, + const std::string& server_config, + QuicVersion quic_version, + base::StringPiece chlo_hash, + const QuicTagVector& connection_options, + QuicReferenceCountedPointer<ProofSource::Chain>* out_chain, + QuicCryptoProof* proof); + std::unique_ptr<crypto::RSAPrivateKey> private_key_; QuicReferenceCountedPointer<ProofSource::Chain> chain_; std::string signed_certificate_timestamp_;
diff --git a/net/quic/chromium/crypto/proof_test_chromium.cc b/net/quic/chromium/crypto/proof_test_chromium.cc index 023a433..eb4a61b 100644 --- a/net/quic/chromium/crypto/proof_test_chromium.cc +++ b/net/quic/chromium/crypto/proof_test_chromium.cc
@@ -65,7 +65,7 @@ bool ok; string error_details; std::unique_ptr<ProofVerifyContext> verify_context( - CryptoTestUtils::ProofVerifyContextForTesting()); + crypto_test_utils::ProofVerifyContextForTesting()); std::unique_ptr<TestProofVerifierCallback> callback( new TestProofVerifierCallback(&comp_callback, &ok, &error_details)); @@ -124,9 +124,10 @@ // TODO(rtenneti): Enable testing of ProofVerifier. See http://crbug.com/514468. TEST_P(ProofTest, DISABLED_Verify) { - std::unique_ptr<ProofSource> source(CryptoTestUtils::ProofSourceForTesting()); + std::unique_ptr<ProofSource> source( + crypto_test_utils::ProofSourceForTesting()); std::unique_ptr<ProofVerifier> verifier( - CryptoTestUtils::ProofVerifierForTesting()); + crypto_test_utils::ProofVerifierForTesting()); const string server_config = "server config bytes"; const string hostname = "test.example.com"; @@ -135,18 +136,30 @@ const string second_chlo_hash = "first chlo hash bytes"; const QuicVersion quic_version = GetParam(); + bool called = false; + bool first_called = false; + bool ok, first_ok; QuicReferenceCountedPointer<ProofSource::Chain> chain; QuicReferenceCountedPointer<ProofSource::Chain> first_chain; string error_details; QuicCryptoProof proof, first_proof; QuicSocketAddress server_addr; - ASSERT_TRUE(source->GetProof(server_addr, hostname, server_config, - quic_version, first_chlo_hash, QuicTagVector(), - &first_chain, &first_proof)); - ASSERT_TRUE(source->GetProof(server_addr, hostname, server_config, - quic_version, second_chlo_hash, QuicTagVector(), - &chain, &proof)); + std::unique_ptr<ProofSource::Callback> cb( + new TestCallback(&called, &ok, &chain, &proof)); + std::unique_ptr<ProofSource::Callback> first_cb( + new TestCallback(&first_called, &first_ok, &first_chain, &first_proof)); + + // GetProof here expects the async method to invoke the callback + // synchronously. + source->GetProof(server_addr, hostname, server_config, quic_version, + first_chlo_hash, QuicTagVector(), std::move(first_cb)); + source->GetProof(server_addr, hostname, server_config, quic_version, + second_chlo_hash, QuicTagVector(), std::move(cb)); + ASSERT_TRUE(called); + ASSERT_TRUE(first_called); + ASSERT_TRUE(ok); + ASSERT_TRUE(first_ok); // Check that the proof source is caching correctly: ASSERT_EQ(first_chain->certs, chain->certs); @@ -176,53 +189,28 @@ first_chlo_hash, wrong_certs, corrupt_signature, false); } -TEST_P(ProofTest, VerifySourceAsync) { - std::unique_ptr<ProofSource> source(CryptoTestUtils::ProofSourceForTesting()); - - const string server_config = "server config bytes"; - const string hostname = "test.example.com"; - const string first_chlo_hash = "first chlo hash bytes"; - const string second_chlo_hash = "first chlo hash bytes"; - const QuicVersion quic_version = GetParam(); - QuicSocketAddress server_addr; - - // Call synchronous version - QuicReferenceCountedPointer<ProofSource::Chain> expected_chain; - QuicCryptoProof expected_proof; - ASSERT_TRUE(source->GetProof(server_addr, hostname, server_config, - quic_version, first_chlo_hash, QuicTagVector(), - &expected_chain, &expected_proof)); - - // Call asynchronous version and compare results - bool called = false; - bool ok; - QuicReferenceCountedPointer<ProofSource::Chain> chain; - QuicCryptoProof proof; - std::unique_ptr<ProofSource::Callback> cb( - new TestCallback(&called, &ok, &chain, &proof)); - source->GetProof(server_addr, hostname, server_config, quic_version, - first_chlo_hash, QuicTagVector(), std::move(cb)); - // TODO(gredner): whan GetProof really invokes the callback asynchronously, - // figure out what to do here. - ASSERT_TRUE(called); - ASSERT_TRUE(ok); - EXPECT_THAT(chain->certs, ::testing::ContainerEq(expected_chain->certs)); - EXPECT_EQ(proof.leaf_cert_scts, expected_proof.leaf_cert_scts); -} - TEST_P(ProofTest, UseAfterFree) { - std::unique_ptr<ProofSource> source(CryptoTestUtils::ProofSourceForTesting()); + std::unique_ptr<ProofSource> source( + crypto_test_utils::ProofSourceForTesting()); const string server_config = "server config bytes"; const string hostname = "test.example.com"; const string chlo_hash = "proof nonce bytes"; + bool called = false; + bool ok; QuicReferenceCountedPointer<ProofSource::Chain> chain; string error_details; QuicCryptoProof proof; QuicSocketAddress server_addr; + std::unique_ptr<ProofSource::Callback> cb( + new TestCallback(&called, &ok, &chain, &proof)); - ASSERT_TRUE(source->GetProof(server_addr, hostname, server_config, GetParam(), - chlo_hash, QuicTagVector(), &chain, &proof)); + // GetProof here expects the async method to invoke the callback + // synchronously. + source->GetProof(server_addr, hostname, server_config, GetParam(), chlo_hash, + QuicTagVector(), std::move(cb)); + ASSERT_TRUE(called); + ASSERT_TRUE(ok); // Make sure we can safely access results after deleting where they came from. EXPECT_FALSE(chain->HasOneRef());
diff --git a/net/quic/chromium/crypto_test_utils_chromium.cc b/net/quic/chromium/crypto_test_utils_chromium.cc index a7b8df41..691cb18 100644 --- a/net/quic/chromium/crypto_test_utils_chromium.cc +++ b/net/quic/chromium/crypto_test_utils_chromium.cc
@@ -79,8 +79,9 @@ } // namespace -// static -std::unique_ptr<ProofSource> CryptoTestUtils::ProofSourceForTesting() { +namespace crypto_test_utils { + +std::unique_ptr<ProofSource> ProofSourceForTesting() { std::unique_ptr<ProofSourceChromium> source(new ProofSourceChromium()); base::FilePath certs_dir = GetTestCertsDirectory(); CHECK(source->Initialize( @@ -90,8 +91,7 @@ return std::move(source); } -// static -std::unique_ptr<ProofVerifier> CryptoTestUtils::ProofVerifierForTesting() { +std::unique_ptr<ProofVerifier> ProofVerifierForTesting() { // TODO(rch): use a real cert verifier? std::unique_ptr<MockCertVerifier> cert_verifier(new MockCertVerifier()); net::CertVerifyResult verify_result; @@ -109,12 +109,13 @@ base::WrapUnique(new CTPolicyEnforcer), "quic_root.crt"); } -// static -ProofVerifyContext* CryptoTestUtils::ProofVerifyContextForTesting() { +ProofVerifyContext* ProofVerifyContextForTesting() { return new ProofVerifyContextChromium(/*cert_verify_flags=*/0, NetLogWithSource()); } +} // namespace crypto_test_utils + } // namespace test } // namespace net
diff --git a/net/quic/chromium/quic_chromium_client_session_test.cc b/net/quic/chromium/quic_chromium_client_session_test.cc index 77f6400..e8772e5 100644 --- a/net/quic/chromium/quic_chromium_client_session_test.cc +++ b/net/quic/chromium/quic_chromium_client_session_test.cc
@@ -82,7 +82,7 @@ : public ::testing::TestWithParam<QuicVersion> { protected: QuicChromiumClientSessionTest() - : crypto_config_(CryptoTestUtils::ProofVerifierForTesting()), + : crypto_config_(crypto_test_utils::ProofVerifierForTesting()), default_read_(new MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)), socket_data_( new SequencedSocketData(default_read_.get(), 1, nullptr, 0)),
diff --git a/net/quic/chromium/quic_chromium_client_stream.h b/net/quic/chromium/quic_chromium_client_stream.h index 01afae7..9facd0c 100644 --- a/net/quic/chromium/quic_chromium_client_stream.h +++ b/net/quic/chromium/quic_chromium_client_stream.h
@@ -125,6 +125,7 @@ bool IsFirstStream(); using QuicSpdyStream::HasBufferedData; + using QuicStream::sequencer; private: void NotifyDelegateOfHeadersCompleteLater(SpdyHeaderBlock headers,
diff --git a/net/quic/chromium/quic_chromium_client_stream_test.cc b/net/quic/chromium/quic_chromium_client_stream_test.cc index 03be8e8..9dc3210 100644 --- a/net/quic/chromium/quic_chromium_client_stream_test.cc +++ b/net/quic/chromium/quic_chromium_client_stream_test.cc
@@ -168,7 +168,7 @@ : public ::testing::TestWithParam<QuicVersion> { public: QuicChromiumClientStreamTest() - : crypto_config_(CryptoTestUtils::ProofVerifierForTesting()), + : crypto_config_(crypto_test_utils::ProofVerifierForTesting()), session_(new MockQuicConnection(&helper_, &alarm_factory_, Perspective::IS_CLIENT,
diff --git a/net/quic/chromium/quic_end_to_end_unittest.cc b/net/quic/chromium/quic_end_to_end_unittest.cc index 867d2ff..30e89f18 100644 --- a/net/quic/chromium/quic_end_to_end_unittest.cc +++ b/net/quic/chromium/quic_end_to_end_unittest.cc
@@ -179,7 +179,7 @@ kInitialSessionFlowControlWindowForTest); server_config_options_.token_binding_params = QuicTagVector{kTB10, kP256}; server_.reset(new QuicSimpleServer( - CryptoTestUtils::ProofSourceForTesting(), server_config_, + crypto_test_utils::ProofSourceForTesting(), server_config_, server_config_options_, AllSupportedVersions(), &response_cache_)); server_->Listen(server_address_); server_address_ = server_->server_address();
diff --git a/net/quic/chromium/quic_http_stream.cc b/net/quic/chromium/quic_http_stream.cc index c00c649..f824b46 100644 --- a/net/quic/chromium/quic_http_stream.cc +++ b/net/quic/chromium/quic_http_stream.cc
@@ -19,6 +19,7 @@ #include "net/log/net_log_source.h" #include "net/quic/chromium/quic_http_utils.h" #include "net/quic/core/quic_client_promised_info.h" +#include "net/quic/core/quic_stream_sequencer.h" #include "net/quic/core/quic_utils.h" #include "net/quic/core/spdy_utils.h" #include "net/spdy/spdy_frame_builder.h" @@ -376,7 +377,10 @@ // bytes. Change this to include QUIC overhead as well. int64_t total_received_bytes = headers_bytes_received_; if (stream_) { - total_received_bytes += stream_->stream_bytes_read(); + DCHECK_LE(stream_->sequencer()->NumBytesConsumed(), + stream_->stream_bytes_read()); + // Only count the uniquely received bytes. + total_received_bytes += stream_->sequencer()->NumBytesConsumed(); } else { total_received_bytes += closed_stream_received_bytes_; } @@ -812,7 +816,10 @@ } if (!stream_) return; - closed_stream_received_bytes_ = stream_->stream_bytes_read(); + DCHECK_LE(stream_->sequencer()->NumBytesConsumed(), + stream_->stream_bytes_read()); + // Only count the uniquely received bytes. + closed_stream_received_bytes_ = stream_->sequencer()->NumBytesConsumed(); closed_stream_sent_bytes_ = stream_->stream_bytes_written(); closed_is_first_stream_ = stream_->IsFirstStream(); stream_ = nullptr;
diff --git a/net/quic/chromium/quic_http_stream_test.cc b/net/quic/chromium/quic_http_stream_test.cc index 6f4e4ec..d57d2db2 100644 --- a/net/quic/chromium/quic_http_stream_test.cc +++ b/net/quic/chromium/quic_http_stream_test.cc
@@ -202,7 +202,7 @@ QuicHttpStreamTest() : use_closing_stream_(false), - crypto_config_(CryptoTestUtils::ProofVerifierForTesting()), + crypto_config_(crypto_test_utils::ProofVerifierForTesting()), read_buffer_(new IOBufferWithSize(4096)), promise_id_(kServerDataStreamId1), stream_id_(kClientDataStreamId1),
diff --git a/net/quic/chromium/quic_network_transaction_unittest.cc b/net/quic/chromium/quic_network_transaction_unittest.cc index 9c243c9..0021013 100644 --- a/net/quic/chromium/quic_network_transaction_unittest.cc +++ b/net/quic/chromium/quic_network_transaction_unittest.cc
@@ -2798,7 +2798,7 @@ GetRequestHeaders("POST", "https", "/"), &offset)); std::unique_ptr<QuicEncryptedPacket> packet; - if (version_ > QUIC_VERSION_35) { + if (version_ == QUIC_VERSION_36) { packet = ConstructClientForceHolDataPacket(3, kClientDataStreamId1, true, true, &offset, "1"); } else {
diff --git a/net/quic/chromium/quic_stream_factory_test.cc b/net/quic/chromium/quic_stream_factory_test.cc index e40a2bd..4b9f10f 100644 --- a/net/quic/chromium/quic_stream_factory_test.cc +++ b/net/quic/chromium/quic_stream_factory_test.cc
@@ -5312,7 +5312,7 @@ EXPECT_EQ(OK, callback_.WaitForResult()); QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); - if (session->connection()->version() > QUIC_VERSION_35) { + if (session->connection()->version() == QUIC_VERSION_36) { EXPECT_TRUE(session->force_hol_blocking()); } else { EXPECT_FALSE(session->force_hol_blocking());
diff --git a/net/quic/chromium/quic_test_packet_maker.cc b/net/quic/chromium/quic_test_packet_maker.cc index 43a99db..d80ecda 100644 --- a/net/quic/chromium/quic_test_packet_maker.cc +++ b/net/quic/chromium/quic_test_packet_maker.cc
@@ -118,9 +118,8 @@ std::unique_ptr<QuicPacket> packet( BuildUnsizedDataPacket(&framer, header, frames)); char buffer[kMaxPacketSize]; - size_t encrypted_size = framer.EncryptPayload(ENCRYPTION_NONE, /*path_id=*/0u, - header.packet_number, *packet, - buffer, kMaxPacketSize); + size_t encrypted_size = framer.EncryptPayload( + ENCRYPTION_NONE, header.packet_number, *packet, buffer, kMaxPacketSize); EXPECT_NE(0u, encrypted_size); QuicReceivedPacket encrypted(buffer, encrypted_size, QuicTime::Zero(), false); return std::unique_ptr<QuicReceivedPacket>(encrypted.Clone()); @@ -170,9 +169,8 @@ std::unique_ptr<QuicPacket> packet( BuildUnsizedDataPacket(&framer, header, frames)); char buffer[kMaxPacketSize]; - size_t encrypted_size = framer.EncryptPayload(ENCRYPTION_NONE, /*path_id=*/0u, - header.packet_number, *packet, - buffer, kMaxPacketSize); + size_t encrypted_size = framer.EncryptPayload( + ENCRYPTION_NONE, header.packet_number, *packet, buffer, kMaxPacketSize); EXPECT_NE(0u, encrypted_size); QuicReceivedPacket encrypted(buffer, encrypted_size, clock_->Now(), false); return std::unique_ptr<QuicReceivedPacket>(encrypted.Clone()); @@ -259,9 +257,8 @@ std::unique_ptr<QuicPacket> packet( BuildUnsizedDataPacket(&framer, header, frames)); char buffer[kMaxPacketSize]; - size_t encrypted_size = framer.EncryptPayload(ENCRYPTION_NONE, /*path_id=*/0u, - header.packet_number, *packet, - buffer, kMaxPacketSize); + size_t encrypted_size = framer.EncryptPayload( + ENCRYPTION_NONE, header.packet_number, *packet, buffer, kMaxPacketSize); EXPECT_NE(0u, encrypted_size); QuicReceivedPacket encrypted(buffer, encrypted_size, clock_->Now(), false); return std::unique_ptr<QuicReceivedPacket>(encrypted.Clone()); @@ -617,9 +614,8 @@ std::unique_ptr<QuicPacket> packet( BuildUnsizedDataPacket(&framer, header, frames)); char buffer[kMaxPacketSize]; - size_t encrypted_size = framer.EncryptPayload(ENCRYPTION_NONE, /*path_id=*/0u, - header.packet_number, *packet, - buffer, kMaxPacketSize); + size_t encrypted_size = framer.EncryptPayload( + ENCRYPTION_NONE, header.packet_number, *packet, buffer, kMaxPacketSize); EXPECT_NE(0u, encrypted_size); QuicReceivedPacket encrypted(buffer, encrypted_size, clock_->Now(), false); return std::unique_ptr<QuicReceivedPacket>(encrypted.Clone());
diff --git a/net/quic/core/crypto/aead_base_decrypter.cc b/net/quic/core/crypto/aead_base_decrypter.cc index 5798424..08345dfd 100644 --- a/net/quic/core/crypto/aead_base_decrypter.cc +++ b/net/quic/core/crypto/aead_base_decrypter.cc
@@ -116,7 +116,6 @@ } bool AeadBaseDecrypter::DecryptPacket(QuicVersion /*version*/, - QuicPathId path_id, QuicPacketNumber packet_number, StringPiece associated_data, StringPiece ciphertext, @@ -135,10 +134,7 @@ uint8_t nonce[sizeof(nonce_prefix_) + sizeof(packet_number)]; const size_t nonce_size = nonce_prefix_size_ + sizeof(packet_number); memcpy(nonce, nonce_prefix_, nonce_prefix_size_); - uint64_t path_id_packet_number = - QuicUtils::PackPathIdAndPacketNumber(path_id, packet_number); - memcpy(nonce + nonce_prefix_size_, &path_id_packet_number, - sizeof(path_id_packet_number)); + memcpy(nonce + nonce_prefix_size_, &packet_number, sizeof(packet_number)); if (!EVP_AEAD_CTX_open( ctx_.get(), reinterpret_cast<uint8_t*>(output), output_length, max_output_length, reinterpret_cast<const uint8_t*>(nonce),
diff --git a/net/quic/core/crypto/aead_base_decrypter.h b/net/quic/core/crypto/aead_base_decrypter.h index 58f8fb5..23fbdd6f 100644 --- a/net/quic/core/crypto/aead_base_decrypter.h +++ b/net/quic/core/crypto/aead_base_decrypter.h
@@ -30,7 +30,6 @@ bool SetPreliminaryKey(base::StringPiece key) override; bool SetDiversificationNonce(const DiversificationNonce& nonce) override; bool DecryptPacket(QuicVersion version, - QuicPathId path_id, QuicPacketNumber packet_number, base::StringPiece associated_data, base::StringPiece ciphertext,
diff --git a/net/quic/core/crypto/aead_base_encrypter.cc b/net/quic/core/crypto/aead_base_encrypter.cc index 1420b00..3318389 100644 --- a/net/quic/core/crypto/aead_base_encrypter.cc +++ b/net/quic/core/crypto/aead_base_encrypter.cc
@@ -103,7 +103,6 @@ } bool AeadBaseEncrypter::EncryptPacket(QuicVersion /*version*/, - QuicPathId path_id, QuicPacketNumber packet_number, StringPiece associated_data, StringPiece plaintext, @@ -119,10 +118,8 @@ const size_t nonce_size = nonce_prefix_size_ + sizeof(packet_number); QUIC_ALIGNED(4) char nonce_buffer[kMaxNonceSize]; memcpy(nonce_buffer, nonce_prefix_, nonce_prefix_size_); - uint64_t path_id_packet_number = - QuicUtils::PackPathIdAndPacketNumber(path_id, packet_number); - memcpy(nonce_buffer + nonce_prefix_size_, &path_id_packet_number, - sizeof(path_id_packet_number)); + memcpy(nonce_buffer + nonce_prefix_size_, &packet_number, + sizeof(packet_number)); if (!Encrypt(StringPiece(nonce_buffer, nonce_size), associated_data, plaintext, reinterpret_cast<unsigned char*>(output))) {
diff --git a/net/quic/core/crypto/aead_base_encrypter.h b/net/quic/core/crypto/aead_base_encrypter.h index 76362766..fcbe039 100644 --- a/net/quic/core/crypto/aead_base_encrypter.h +++ b/net/quic/core/crypto/aead_base_encrypter.h
@@ -28,7 +28,6 @@ bool SetKey(base::StringPiece key) override; bool SetNoncePrefix(base::StringPiece nonce_prefix) override; bool EncryptPacket(QuicVersion version, - QuicPathId path_id, QuicPacketNumber packet_number, base::StringPiece associated_data, base::StringPiece plaintext,
diff --git a/net/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc b/net/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc index 4a04d21..c57d6707 100644 --- a/net/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc +++ b/net/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc
@@ -203,19 +203,15 @@ StringPiece nonce, StringPiece associated_data, StringPiece ciphertext) { - QuicPathId path_id = kDefaultPathId; QuicPacketNumber packet_number; StringPiece nonce_prefix(nonce.data(), nonce.size() - sizeof(packet_number)); decrypter->SetNoncePrefix(nonce_prefix); memcpy(&packet_number, nonce.data() + nonce_prefix.size(), sizeof(packet_number)); - path_id = static_cast<QuicPathId>( - packet_number >> 8 * (sizeof(packet_number) - sizeof(path_id))); - packet_number &= UINT64_C(0x00FFFFFFFFFFFFFF); std::unique_ptr<char[]> output(new char[ciphertext.length()]); size_t output_length = 0; const bool success = decrypter->DecryptPacket( - QuicVersionMax(), path_id, packet_number, associated_data, ciphertext, + QuicVersionMax(), packet_number, associated_data, ciphertext, output.get(), &output_length, ciphertext.length()); if (!success) { return nullptr;
diff --git a/net/quic/core/crypto/cert_compressor_test.cc b/net/quic/core/crypto/cert_compressor_test.cc index 11da033..2ab9094 100644 --- a/net/quic/core/crypto/cert_compressor_test.cc +++ b/net/quic/core/crypto/cert_compressor_test.cc
@@ -49,7 +49,7 @@ chain.push_back("testcert"); static const uint64_t set_hash = 42; std::unique_ptr<CommonCertSets> common_sets( - CryptoTestUtils::MockCommonCertSets(chain[0], set_hash, 1)); + crypto_test_utils::MockCommonCertSets(chain[0], set_hash, 1)); const string compressed = CertCompressor::CompressChain( chain, StringPiece(reinterpret_cast<const char*>(&set_hash), sizeof(set_hash)), @@ -115,7 +115,7 @@ cached_certs, nullptr, &chain)); std::unique_ptr<CommonCertSets> common_sets( - CryptoTestUtils::MockCommonCertSets("foo", 42, 1)); + crypto_test_utils::MockCommonCertSets("foo", 42, 1)); /* incorrect hash and index */ EXPECT_FALSE(CertCompressor::DecompressChain(
diff --git a/net/quic/core/crypto/chacha20_poly1305_decrypter_test.cc b/net/quic/core/crypto/chacha20_poly1305_decrypter_test.cc index 6caa52fc..aa766db 100644 --- a/net/quic/core/crypto/chacha20_poly1305_decrypter_test.cc +++ b/net/quic/core/crypto/chacha20_poly1305_decrypter_test.cc
@@ -117,19 +117,15 @@ StringPiece nonce, StringPiece associated_data, StringPiece ciphertext) { - QuicPathId path_id = kDefaultPathId; QuicPacketNumber packet_number; StringPiece nonce_prefix(nonce.data(), nonce.size() - sizeof(packet_number)); decrypter->SetNoncePrefix(nonce_prefix); memcpy(&packet_number, nonce.data() + nonce_prefix.size(), sizeof(packet_number)); - path_id = static_cast<QuicPathId>( - packet_number >> 8 * (sizeof(packet_number) - sizeof(path_id))); - packet_number &= UINT64_C(0x00FFFFFFFFFFFFFF); std::unique_ptr<char[]> output(new char[ciphertext.length()]); size_t output_length = 0; const bool success = decrypter->DecryptPacket( - QuicVersionMax(), path_id, packet_number, associated_data, ciphertext, + QuicVersionMax(), packet_number, associated_data, ciphertext, output.get(), &output_length, ciphertext.length()); if (!success) { return nullptr;
diff --git a/net/quic/core/crypto/chacha20_poly1305_encrypter_test.cc b/net/quic/core/crypto/chacha20_poly1305_encrypter_test.cc index 0ec53087..9752843 100644 --- a/net/quic/core/crypto/chacha20_poly1305_encrypter_test.cc +++ b/net/quic/core/crypto/chacha20_poly1305_encrypter_test.cc
@@ -94,18 +94,17 @@ ASSERT_TRUE(encrypter.SetNoncePrefix("abcd")); ASSERT_TRUE(decrypter.SetNoncePrefix("abcd")); - QuicPathId path_id = 0x42; QuicPacketNumber packet_number = UINT64_C(0x123456789ABC); string associated_data = "associated_data"; string plaintext = "plaintext"; char encrypted[1024]; size_t len; - ASSERT_TRUE(encrypter.EncryptPacket(QuicVersionMax(), path_id, packet_number, + ASSERT_TRUE(encrypter.EncryptPacket(QuicVersionMax(), packet_number, associated_data, plaintext, encrypted, &len, arraysize(encrypted))); StringPiece ciphertext(encrypted, len); char decrypted[1024]; - ASSERT_TRUE(decrypter.DecryptPacket(QuicVersionMax(), path_id, packet_number, + ASSERT_TRUE(decrypter.DecryptPacket(QuicVersionMax(), packet_number, associated_data, ciphertext, decrypted, &len, arraysize(decrypted))); }
diff --git a/net/quic/core/crypto/channel_id_test.cc b/net/quic/core/crypto/channel_id_test.cc index 0309e65c..38931fd 100644 --- a/net/quic/core/crypto/channel_id_test.cc +++ b/net/quic/core/crypto/channel_id_test.cc
@@ -283,7 +283,7 @@ TEST(ChannelIDTest, SignAndVerify) { std::unique_ptr<ChannelIDSource> source( - CryptoTestUtils::ChannelIDSourceForTesting()); + crypto_test_utils::ChannelIDSourceForTesting()); const string signed_data = "signed data"; const string hostname = "foo.example.com";
diff --git a/net/quic/core/crypto/crypto_framer_test.cc b/net/quic/core/crypto/crypto_framer_test.cc index 5e045a45..4210b5f 100644 --- a/net/quic/core/crypto/crypto_framer_test.cc +++ b/net/quic/core/crypto/crypto_framer_test.cc
@@ -274,8 +274,8 @@ const CryptoHandshakeMessage& message = visitor.messages_[0]; EXPECT_EQ(0xFFAA7733, message.tag()); EXPECT_EQ(2u, message.tag_value_map().size()); - EXPECT_EQ("abcdef", CryptoTestUtils::GetValueForTag(message, 0x12345678)); - EXPECT_EQ("ghijk", CryptoTestUtils::GetValueForTag(message, 0x12345679)); + EXPECT_EQ("abcdef", crypto_test_utils::GetValueForTag(message, 0x12345678)); + EXPECT_EQ("ghijk", crypto_test_utils::GetValueForTag(message, 0x12345679)); } TEST(CryptoFramerTest, ProcessInputWithThreeKeys) { @@ -318,9 +318,9 @@ const CryptoHandshakeMessage& message = visitor.messages_[0]; EXPECT_EQ(0xFFAA7733, message.tag()); EXPECT_EQ(3u, message.tag_value_map().size()); - EXPECT_EQ("abcdef", CryptoTestUtils::GetValueForTag(message, 0x12345678)); - EXPECT_EQ("ghijk", CryptoTestUtils::GetValueForTag(message, 0x12345679)); - EXPECT_EQ("lmnopqr", CryptoTestUtils::GetValueForTag(message, 0x1234567A)); + EXPECT_EQ("abcdef", crypto_test_utils::GetValueForTag(message, 0x12345678)); + EXPECT_EQ("ghijk", crypto_test_utils::GetValueForTag(message, 0x12345679)); + EXPECT_EQ("lmnopqr", crypto_test_utils::GetValueForTag(message, 0x1234567A)); } TEST(CryptoFramerTest, ProcessInputIncrementally) { @@ -357,8 +357,8 @@ const CryptoHandshakeMessage& message = visitor.messages_[0]; EXPECT_EQ(0xFFAA7733, message.tag()); EXPECT_EQ(2u, message.tag_value_map().size()); - EXPECT_EQ("abcdef", CryptoTestUtils::GetValueForTag(message, 0x12345678)); - EXPECT_EQ("ghijk", CryptoTestUtils::GetValueForTag(message, 0x12345679)); + EXPECT_EQ("abcdef", crypto_test_utils::GetValueForTag(message, 0x12345678)); + EXPECT_EQ("ghijk", crypto_test_utils::GetValueForTag(message, 0x12345679)); } TEST(CryptoFramerTest, ProcessInputTagsOutOfOrder) {
diff --git a/net/quic/core/crypto/crypto_secret_boxer.cc b/net/quic/core/crypto/crypto_secret_boxer.cc index 15d0720..a109152 100644 --- a/net/quic/core/crypto/crypto_secret_boxer.cc +++ b/net/quic/core/crypto/crypto_secret_boxer.cc
@@ -108,8 +108,7 @@ for (const string& key : keys_) { if (decrypter->SetKey(key)) { decrypter->SetNoncePrefix(nonce_prefix); - if (decrypter->DecryptPacket(QUIC_VERSION_36, - /*path_id=*/0u, packet_number, + if (decrypter->DecryptPacket(QUIC_VERSION_36, packet_number, /*associated data=*/StringPiece(), ciphertext, plaintext, &plaintext_length, kMaxPacketSize)) {
diff --git a/net/quic/core/crypto/crypto_server_test.cc b/net/quic/core/crypto/crypto_server_test.cc index 941e2fe..67cd077 100644 --- a/net/quic/core/crypto/crypto_server_test.cc +++ b/net/quic/core/crypto/crypto_server_test.cc
@@ -8,7 +8,6 @@ #include <ostream> #include <vector> -#include "crypto/secure_hash.h" #include "net/quic/core/crypto/cert_compressor.h" #include "net/quic/core/crypto/common_cert_set.h" #include "net/quic/core/crypto/crypto_handshake.h" @@ -29,6 +28,7 @@ #include "net/quic/test_tools/quic_crypto_server_config_peer.h" #include "net/quic/test_tools/quic_test_utils.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/boringssl/src/include/openssl/sha.h" using base::StringPiece; using std::string; @@ -107,7 +107,7 @@ client_address_(QuicIpAddress::Loopback4(), 1234), config_(QuicCryptoServerConfig::TESTING, rand_, - CryptoTestUtils::ProofSourceForTesting()), + crypto_test_utils::ProofSourceForTesting()), peer_(&config_), compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), @@ -149,19 +149,15 @@ pub_hex_ = "#" + QuicTextUtils::HexEncode(public_value, sizeof(public_value)); - // clang-format off - CryptoHandshakeMessage client_hello = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "AEAD", "AESG", - "KEXS", "C255", - "PUBS", pub_hex_.c_str(), - "NONC", nonce_hex_.c_str(), - "CSCT", "", - "VER\0", client_version_string_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage client_hello = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"CSCT", ""}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); ShouldSucceed(client_hello); // The message should be rejected because the source-address token is // missing. @@ -386,7 +382,7 @@ } string XlctHexString() { - uint64_t xlct = CryptoTestUtils::LeafCertHashForTesting(); + uint64_t xlct = crypto_test_utils::LeafCertHashForTesting(); return "#" + QuicTextUtils::HexEncode(reinterpret_cast<char*>(&xlct), sizeof(xlct)); } @@ -434,15 +430,11 @@ // clang-format on for (size_t i = 0; i < arraysize(kBadSNIs); i++) { - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "SNI", kBadSNIs[i], - "VER\0", client_version_string_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"SNI", kBadSNIs[i]}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); ShouldFailMentioning("SNI", msg); const HandshakeFailureReason kRejectReasons[] = { SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; @@ -454,18 +446,14 @@ // Check that the server replies with a default certificate when no SNI is // specified. The CHLO is constructed to generate a REJ with certs, so must // not contain a valid STK, and must include PDMD. - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "AEAD", "AESG", - "KEXS", "C255", - "PUBS", pub_hex_.c_str(), - "NONC", nonce_hex_.c_str(), - "PDMD", "X509", - "VER\0", client_version_string_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"PDMD", "X509"}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); ShouldSucceed(msg); StringPiece cert, proof, cert_sct; @@ -483,19 +471,15 @@ TEST_P(CryptoServerTest, RejectTooLarge) { // Check that the server replies with no certificate when a CHLO is // constructed with a PDMD but no SKT when the REJ would be too large. - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "AEAD", "AESG", - "KEXS", "C255", - "PUBS", pub_hex_.c_str(), - "NONC", nonce_hex_.c_str(), - "PDMD", "X509", - "VER\0", client_version_string_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"PDMD", "X509"}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); // The REJ will be larger than the CHLO so no PROF or CRT will be sent. config_.set_chlo_multiplier(1); @@ -514,19 +498,15 @@ // When the CHLO packet is large enough, ensure that a full REJ is sent. chlo_packet_size_ *= 2; - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "AEAD", "AESG", - "KEXS", "C255", - "PUBS", pub_hex_.c_str(), - "NONC", nonce_hex_.c_str(), - "PDMD", "X509", - "VER\0", client_version_string_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"PDMD", "X509"}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); // The REJ will be larger than the CHLO so no PROF or CRT will be sent. config_.set_chlo_multiplier(1); @@ -544,20 +524,16 @@ TEST_P(CryptoServerTest, RejectTooLargeButValidSTK) { // Check that the server replies with no certificate when a CHLO is // constructed with a PDMD but no SKT when the REJ would be too large. - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "AEAD", "AESG", - "KEXS", "C255", - "PUBS", pub_hex_.c_str(), - "NONC", nonce_hex_.c_str(), - "#004b5453", srct_hex_.c_str(), - "PDMD", "X509", - "VER\0", client_version_string_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"#004b5453", srct_hex_}, + {"PDMD", "X509"}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); // The REJ will be larger than the CHLO so no PROF or CRT will be sent. config_.set_chlo_multiplier(1); @@ -575,13 +551,11 @@ } TEST_P(CryptoServerTest, TooSmall) { - // clang-format off - ShouldFailMentioning("too small", CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "VER\0", client_version_string_.c_str(), - nullptr)); - // clang-format on + ShouldFailMentioning( + "too small", + crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, {"VER\0", client_version_string_.c_str()}})); + const HandshakeFailureReason kRejectReasons[] = { SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); @@ -599,14 +573,11 @@ // clang-format on for (size_t i = 0; i < arraysize(kBadSourceAddressTokens); i++) { - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "STK", kBadSourceAddressTokens[i], - "VER\0", client_version_string_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), nullptr); - // clang-format on + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"STK", kBadSourceAddressTokens[i]}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); ShouldSucceed(msg); const HandshakeFailureReason kRejectReasons[] = { SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; @@ -625,37 +596,31 @@ for (size_t i = 0; i < arraysize(kBadNonces); i++) { // Invalid nonces should be ignored, in an inchoate CHLO. - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "NONC", kBadNonces[i], - "VER\0", client_version_string_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"NONC", kBadNonces[i]}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + ShouldSucceed(msg); const HandshakeFailureReason kRejectReasons[] = { SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); // Invalid nonces should result in CLIENT_NONCE_INVALID_FAILURE. - // clang-format off - CryptoHandshakeMessage msg1 = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "AEAD", "AESG", - "KEXS", "C255", - "SCID", scid_hex_.c_str(), - "#004b5453", srct_hex_.c_str(), - "PUBS", pub_hex_.c_str(), - "NONC", kBadNonces[i], - "NONP", kBadNonces[i], - "XLCT", XlctHexString().c_str(), - "VER\0", client_version_string_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage msg1 = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", srct_hex_}, + {"PUBS", pub_hex_}, + {"NONC", kBadNonces[i]}, + {"NONP", kBadNonces[i]}, + {"XLCT", XlctHexString()}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); ShouldSucceed(msg1); @@ -668,34 +633,26 @@ TEST_P(CryptoServerTest, NoClientNonce) { // No client nonces should result in INCHOATE_HELLO_FAILURE. - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "VER\0", client_version_string_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + + CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); ShouldSucceed(msg); const HandshakeFailureReason kRejectReasons[] = { SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); - // clang-format off - CryptoHandshakeMessage msg1 = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "AEAD", "AESG", - "KEXS", "C255", - "SCID", scid_hex_.c_str(), - "#004b5453", srct_hex_.c_str(), - "PUBS", pub_hex_.c_str(), - "XLCT", XlctHexString().c_str(), - "VER\0", client_version_string_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage msg1 = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", srct_hex_}, + {"PUBS", pub_hex_}, + {"XLCT", XlctHexString()}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); ShouldSucceed(msg1); CheckRejectTag(); @@ -714,14 +671,9 @@ string bad_version = QuicTagToString(QuicVersionToQuicTag(supported_versions_.back())); - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "VER\0", bad_version.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, {"VER\0", bad_version}}, kClientHelloMinimumSize); + ShouldFailMentioning("Downgrade", msg); const HandshakeFailureReason kRejectReasons[] = { SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; @@ -730,20 +682,17 @@ TEST_P(CryptoServerTest, CorruptServerConfig) { // This tests corrupted server config. - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "AEAD", "AESG", - "KEXS", "C255", - "SCID", (string(1, 'X') + scid_hex_).c_str(), - "#004b5453", srct_hex_.c_str(), - "PUBS", pub_hex_.c_str(), - "NONC", nonce_hex_.c_str(), - "VER\0", client_version_string_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", (string(1, 'X') + scid_hex_)}, + {"#004b5453", srct_hex_}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + ShouldSucceed(msg); CheckRejectTag(); const HandshakeFailureReason kRejectReasons[] = { @@ -753,21 +702,18 @@ TEST_P(CryptoServerTest, CorruptSourceAddressToken) { // This tests corrupted source address token. - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "AEAD", "AESG", - "KEXS", "C255", - "SCID", scid_hex_.c_str(), - "#004b5453", (string(1, 'X') + srct_hex_).c_str(), - "PUBS", pub_hex_.c_str(), - "NONC", nonce_hex_.c_str(), - "XLCT", XlctHexString().c_str(), - "VER\0", client_version_string_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", (string(1, 'X') + srct_hex_)}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"XLCT", XlctHexString()}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + ShouldSucceed(msg); CheckRejectTag(); const HandshakeFailureReason kRejectReasons[] = { @@ -777,21 +723,18 @@ TEST_P(CryptoServerTest, CorruptClientNonceAndSourceAddressToken) { // This test corrupts client nonce and source address token. - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "AEAD", "AESG", - "KEXS", "C255", - "SCID", scid_hex_.c_str(), - "#004b5453", (string(1, 'X') + srct_hex_).c_str(), - "PUBS", pub_hex_.c_str(), - "NONC", (string(1, 'X') + nonce_hex_).c_str(), - "XLCT", XlctHexString().c_str(), - "VER\0", client_version_string_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", (string(1, 'X') + srct_hex_)}, + {"PUBS", pub_hex_}, + {"NONC", (string(1, 'X') + nonce_hex_)}, + {"XLCT", XlctHexString()}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + ShouldSucceed(msg); CheckRejectTag(); const HandshakeFailureReason kRejectReasons[] = { @@ -801,23 +744,20 @@ TEST_P(CryptoServerTest, CorruptMultipleTags) { // This test corrupts client nonce, server nonce and source address token. - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "AEAD", "AESG", - "KEXS", "C255", - "SCID", scid_hex_.c_str(), - "#004b5453", (string(1, 'X') + srct_hex_).c_str(), - "PUBS", pub_hex_.c_str(), - "NONC", (string(1, 'X') + nonce_hex_).c_str(), - "NONP", (string(1, 'X') + nonce_hex_).c_str(), - "SNO\0", (string(1, 'X') + nonce_hex_).c_str(), - "XLCT", XlctHexString().c_str(), - "VER\0", client_version_string_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", (string(1, 'X') + srct_hex_)}, + {"PUBS", pub_hex_}, + {"NONC", (string(1, 'X') + nonce_hex_)}, + {"NONP", (string(1, 'X') + nonce_hex_)}, + {"SNO\0", (string(1, 'X') + nonce_hex_)}, + {"XLCT", XlctHexString()}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + ShouldSucceed(msg); CheckRejectTag(); @@ -829,22 +769,18 @@ TEST_P(CryptoServerTest, NoServerNonce) { // When no server nonce is present and no strike register is configured, // the CHLO should be rejected. - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "AEAD", "AESG", - "KEXS", "C255", - "SCID", scid_hex_.c_str(), - "#004b5453", srct_hex_.c_str(), - "PUBS", pub_hex_.c_str(), - "NONC", nonce_hex_.c_str(), - "NONP", nonce_hex_.c_str(), - "XLCT", XlctHexString().c_str(), - "VER\0", client_version_string_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", srct_hex_}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"NONP", nonce_hex_}, + {"XLCT", XlctHexString()}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); ShouldSucceed(msg); @@ -856,22 +792,20 @@ TEST_P(CryptoServerTest, ProofForSuppliedServerConfig) { client_address_ = QuicSocketAddress(QuicIpAddress::Loopback6(), 1234); - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "AEAD", "AESG", - "KEXS", "C255", - "PDMD", "X509", - "SCID", kOldConfigId, - "#004b5453", srct_hex_.c_str(), - "PUBS", pub_hex_.c_str(), - "NONC", nonce_hex_.c_str(), - "NONP", "123456789012345678901234567890", - "VER\0", client_version_string_.c_str(), - "XLCT", XlctHexString().c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"PDMD", "X509"}, + {"SCID", kOldConfigId}, + {"#004b5453", srct_hex_}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"NONP", "123456789012345678901234567890"}, + {"VER\0", client_version_string_}, + {"XLCT", XlctHexString()}}, + kClientHelloMinimumSize); + ShouldSucceed(msg); // The message should be rejected because the source-address token is no // longer valid. @@ -900,9 +834,9 @@ // Check that the proof in the REJ message is valid. std::unique_ptr<ProofVerifier> proof_verifier( - CryptoTestUtils::ProofVerifierForTesting()); + crypto_test_utils::ProofVerifierForTesting()); std::unique_ptr<ProofVerifyContext> verify_context( - CryptoTestUtils::ProofVerifyContextForTesting()); + crypto_test_utils::ProofVerifyContextForTesting()); std::unique_ptr<ProofVerifyDetails> details; string error_details; std::unique_ptr<ProofVerifierCallback> callback( @@ -917,51 +851,44 @@ } TEST_P(CryptoServerTest, RejectInvalidXlct) { - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "AEAD", "AESG", - "KEXS", "C255", - "SCID", scid_hex_.c_str(), - "#004b5453", srct_hex_.c_str(), - "PUBS", pub_hex_.c_str(), - "NONC", nonce_hex_.c_str(), - "VER\0", client_version_string_.c_str(), - "XLCT", "#0102030405060708", - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", srct_hex_}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"VER\0", client_version_string_}, + {"XLCT", "#0102030405060708"}}, + kClientHelloMinimumSize); + // If replay protection isn't disabled, then // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false // and cause ProcessClientHello to exit early (and generate a REJ message). config_.set_replay_protection(false); ShouldSucceed(msg); - // clang-format off + const HandshakeFailureReason kRejectReasons[] = { - INVALID_EXPECTED_LEAF_CERTIFICATE - }; - // clang-format on + INVALID_EXPECTED_LEAF_CERTIFICATE}; + CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); } TEST_P(CryptoServerTest, ValidXlct) { - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "AEAD", "AESG", - "KEXS", "C255", - "SCID", scid_hex_.c_str(), - "#004b5453", srct_hex_.c_str(), - "PUBS", pub_hex_.c_str(), - "NONC", nonce_hex_.c_str(), - "VER\0", client_version_string_.c_str(), - "XLCT", XlctHexString().c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", srct_hex_}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"VER\0", client_version_string_}, + {"XLCT", XlctHexString()}}, + kClientHelloMinimumSize); + // If replay protection isn't disabled, then // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false // and cause ProcessClientHello to exit early (and generate a REJ message). @@ -972,21 +899,18 @@ } TEST_P(CryptoServerTest, NonceInSHLO) { - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "AEAD", "AESG", - "KEXS", "C255", - "SCID", scid_hex_.c_str(), - "#004b5453", srct_hex_.c_str(), - "PUBS", pub_hex_.c_str(), - "NONC", nonce_hex_.c_str(), - "VER\0", client_version_string_.c_str(), - "XLCT", XlctHexString().c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", srct_hex_}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"VER\0", client_version_string_}, + {"XLCT", XlctHexString()}}, + kClientHelloMinimumSize); + // If replay protection isn't disabled, then // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false // and cause ProcessClientHello to exit early (and generate a REJ message). @@ -1003,19 +927,15 @@ // Install a ProofSource which will unconditionally fail peer_.ResetProofSource(std::unique_ptr<ProofSource>(new FailingProofSource)); - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "AEAD", "AESG", - "KEXS", "C255", - "SCID", scid_hex_.c_str(), - "PUBS", pub_hex_.c_str(), - "NONC", nonce_hex_.c_str(), - "PDMD", "X509", - "VER\0", client_version_string_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"PDMD", "X509"}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); // Just ensure that we don't crash as occurred in b/33916924. ShouldFailMentioning("", msg); @@ -1030,9 +950,9 @@ MockClock clock; QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a, - CryptoTestUtils::ProofSourceForTesting()); + crypto_test_utils::ProofSourceForTesting()); QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b, - CryptoTestUtils::ProofSourceForTesting()); + crypto_test_utils::ProofSourceForTesting()); std::unique_ptr<CryptoHandshakeMessage> scfg_a( a.AddDefaultConfig(&rand_a, &clock, options)); std::unique_ptr<CryptoHandshakeMessage> scfg_b( @@ -1050,10 +970,10 @@ MockClock clock; QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a, - CryptoTestUtils::ProofSourceForTesting()); + crypto_test_utils::ProofSourceForTesting()); rand_b.ChangeValue(); QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b, - CryptoTestUtils::ProofSourceForTesting()); + crypto_test_utils::ProofSourceForTesting()); std::unique_ptr<CryptoHandshakeMessage> scfg_a( a.AddDefaultConfig(&rand_a, &clock, options)); std::unique_ptr<CryptoHandshakeMessage> scfg_b( @@ -1072,7 +992,7 @@ MockClock clock; QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a, - CryptoTestUtils::ProofSourceForTesting()); + crypto_test_utils::ProofSourceForTesting()); std::unique_ptr<CryptoHandshakeMessage> scfg( a.AddDefaultConfig(&rand_a, &clock, options)); @@ -1085,14 +1005,13 @@ scfg->MarkDirty(); const QuicData& serialized(scfg->GetSerialized()); - std::unique_ptr<crypto::SecureHash> hash( - crypto::SecureHash::Create(crypto::SecureHash::SHA256)); - hash->Update(serialized.data(), serialized.length()); - uint8_t digest[16]; - hash->Finish(digest, sizeof(digest)); + uint8_t digest[SHA256_DIGEST_LENGTH]; + SHA256(reinterpret_cast<const uint8_t*>(serialized.data()), + serialized.length(), digest); - ASSERT_EQ(scid.size(), sizeof(digest)); - EXPECT_EQ(0, memcmp(digest, scid_str.c_str(), sizeof(digest))); + // scid is a SHA-256 hash, truncated to 16 bytes. + ASSERT_EQ(scid.size(), 16u); + EXPECT_EQ(0, memcmp(digest, scid_str.c_str(), scid.size())); } class CryptoServerTestNoConfig : public CryptoServerTest { @@ -1103,14 +1022,10 @@ }; TEST_P(CryptoServerTestNoConfig, DontCrash) { - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "VER\0", client_version_string_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + ShouldFailMentioning("No config", msg); const HandshakeFailureReason kRejectReasons[] = { @@ -1129,21 +1044,18 @@ }; TEST_P(CryptoServerTestOldVersion, ServerIgnoresXlct) { - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "AEAD", "AESG", - "KEXS", "C255", - "SCID", scid_hex_.c_str(), - "#004b5453", srct_hex_.c_str(), - "PUBS", pub_hex_.c_str(), - "NONC", nonce_hex_.c_str(), - "VER\0", client_version_string_.c_str(), - "XLCT", "#0100000000000000", - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", srct_hex_}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"VER\0", client_version_string_}, + {"XLCT", "#0100000000000000"}}, + kClientHelloMinimumSize); + // If replay protection isn't disabled, then // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false // and cause ProcessClientHello to exit early (and generate a REJ message). @@ -1154,20 +1066,17 @@ } TEST_P(CryptoServerTestOldVersion, XlctNotRequired) { - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "AEAD", "AESG", - "KEXS", "C255", - "SCID", scid_hex_.c_str(), - "#004b5453", srct_hex_.c_str(), - "PUBS", pub_hex_.c_str(), - "NONC", nonce_hex_.c_str(), - "VER\0", client_version_string_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", srct_hex_}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + // If replay protection isn't disabled, then // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false // and cause ProcessClientHello to exit early (and generate a REJ message).
diff --git a/net/quic/core/crypto/crypto_utils.cc b/net/quic/core/crypto/crypto_utils.cc index c8f1c46..a60a4f2 100644 --- a/net/quic/core/crypto/crypto_utils.cc +++ b/net/quic/core/crypto/crypto_utils.cc
@@ -7,7 +7,6 @@ #include <memory> #include "crypto/hkdf.h" -#include "crypto/secure_hash.h" #include "net/quic/core/crypto/crypto_handshake.h" #include "net/quic/core/crypto/crypto_protocol.h" #include "net/quic/core/crypto/quic_decrypter.h" @@ -17,6 +16,7 @@ #include "net/quic/core/quic_utils.h" #include "net/quic/platform/api/quic_bug_tracker.h" #include "net/quic/platform/api/quic_logging.h" +#include "third_party/boringssl/src/include/openssl/sha.h" using base::StringPiece; using std::string; @@ -295,12 +295,10 @@ void CryptoUtils::HashHandshakeMessage(const CryptoHandshakeMessage& message, string* output) { const QuicData& serialized = message.GetSerialized(); - std::unique_ptr<crypto::SecureHash> hash( - crypto::SecureHash::Create(crypto::SecureHash::SHA256)); - hash->Update(serialized.data(), serialized.length()); - uint8_t digest[32]; - hash->Finish(digest, sizeof(digest)); - output->assign(reinterpret_cast<const char*>(&digest), sizeof(digest)); + uint8_t digest[SHA256_DIGEST_LENGTH]; + SHA256(reinterpret_cast<const uint8_t*>(serialized.data()), + serialized.length(), digest); + output->assign(reinterpret_cast<const char*>(digest), sizeof(digest)); } } // namespace net
diff --git a/net/quic/core/crypto/null_decrypter.cc b/net/quic/core/crypto/null_decrypter.cc index dbc6db9..6f05b4f 100644 --- a/net/quic/core/crypto/null_decrypter.cc +++ b/net/quic/core/crypto/null_decrypter.cc
@@ -38,7 +38,6 @@ } bool NullDecrypter::DecryptPacket(QuicVersion version, - QuicPathId /*path_id*/, QuicPacketNumber /*packet_number*/, StringPiece associated_data, StringPiece ciphertext,
diff --git a/net/quic/core/crypto/null_decrypter.h b/net/quic/core/crypto/null_decrypter.h index 3f6aecb..db93c445 100644 --- a/net/quic/core/crypto/null_decrypter.h +++ b/net/quic/core/crypto/null_decrypter.h
@@ -33,7 +33,6 @@ bool SetPreliminaryKey(base::StringPiece key) override; bool SetDiversificationNonce(const DiversificationNonce& nonce) override; bool DecryptPacket(QuicVersion version, - QuicPathId path_id, QuicPacketNumber packet_number, base::StringPiece associated_data, base::StringPiece ciphertext,
diff --git a/net/quic/core/crypto/null_decrypter_test.cc b/net/quic/core/crypto/null_decrypter_test.cc index 56d20c2c..c70964ca 100644 --- a/net/quic/core/crypto/null_decrypter_test.cc +++ b/net/quic/core/crypto/null_decrypter_test.cc
@@ -24,9 +24,9 @@ NullDecrypter decrypter(Perspective::IS_SERVER); char buffer[256]; size_t length = 0; - ASSERT_TRUE(decrypter.DecryptPacket(QUIC_VERSION_37, kDefaultPathId, 0, - "hello world!", StringPiece(data, len), - buffer, &length, 256)); + ASSERT_TRUE(decrypter.DecryptPacket(QUIC_VERSION_37, 0, "hello world!", + StringPiece(data, len), buffer, &length, + 256)); EXPECT_LT(0u, length); EXPECT_EQ("goodbye!", StringPiece(buffer, length)); } @@ -43,9 +43,9 @@ NullDecrypter decrypter(Perspective::IS_CLIENT); char buffer[256]; size_t length = 0; - ASSERT_TRUE(decrypter.DecryptPacket(QUIC_VERSION_37, kDefaultPathId, 0, - "hello world!", StringPiece(data, len), - buffer, &length, 256)); + ASSERT_TRUE(decrypter.DecryptPacket(QUIC_VERSION_37, 0, "hello world!", + StringPiece(data, len), buffer, &length, + 256)); EXPECT_LT(0u, length); EXPECT_EQ("goodbye!", StringPiece(buffer, length)); } @@ -62,9 +62,9 @@ NullDecrypter decrypter(Perspective::IS_CLIENT); char buffer[256]; size_t length = 0; - ASSERT_TRUE(decrypter.DecryptPacket(QUIC_VERSION_36, kDefaultPathId, 0, - "hello world!", StringPiece(data, len), - buffer, &length, 256)); + ASSERT_TRUE(decrypter.DecryptPacket(QUIC_VERSION_36, 0, "hello world!", + StringPiece(data, len), buffer, &length, + 256)); EXPECT_LT(0u, length); EXPECT_EQ("goodbye!", StringPiece(buffer, length)); } @@ -81,9 +81,9 @@ NullDecrypter decrypter(Perspective::IS_SERVER); char buffer[256]; size_t length = 0; - ASSERT_TRUE(decrypter.DecryptPacket(QUIC_VERSION_36, kDefaultPathId, 0, - "hello world!", StringPiece(data, len), - buffer, &length, 256)); + ASSERT_TRUE(decrypter.DecryptPacket(QUIC_VERSION_36, 0, "hello world!", + StringPiece(data, len), buffer, &length, + 256)); EXPECT_LT(0u, length); EXPECT_EQ("goodbye!", StringPiece(buffer, length)); } @@ -100,9 +100,9 @@ NullDecrypter decrypter(Perspective::IS_CLIENT); char buffer[256]; size_t length = 0; - ASSERT_FALSE(decrypter.DecryptPacket(QUIC_VERSION_35, kDefaultPathId, 0, - "hello world!", StringPiece(data, len), - buffer, &length, 256)); + ASSERT_FALSE(decrypter.DecryptPacket(QUIC_VERSION_35, 0, "hello world!", + StringPiece(data, len), buffer, &length, + 256)); } TEST_F(NullDecrypterTest, ShortInput) { @@ -115,9 +115,9 @@ NullDecrypter decrypter(Perspective::IS_CLIENT); char buffer[256]; size_t length = 0; - ASSERT_FALSE(decrypter.DecryptPacket(QUIC_VERSION_35, kDefaultPathId, 0, - "hello world!", StringPiece(data, len), - buffer, &length, 256)); + ASSERT_FALSE(decrypter.DecryptPacket(QUIC_VERSION_35, 0, "hello world!", + StringPiece(data, len), buffer, &length, + 256)); } } // namespace test
diff --git a/net/quic/core/crypto/null_encrypter.cc b/net/quic/core/crypto/null_encrypter.cc index 986563b..a7cb5d17 100644 --- a/net/quic/core/crypto/null_encrypter.cc +++ b/net/quic/core/crypto/null_encrypter.cc
@@ -26,7 +26,6 @@ } bool NullEncrypter::EncryptPacket(QuicVersion version, - QuicPathId /*path_id*/, QuicPacketNumber /*packet_number*/, StringPiece associated_data, StringPiece plaintext,
diff --git a/net/quic/core/crypto/null_encrypter.h b/net/quic/core/crypto/null_encrypter.h index 96b1bb7..d605d8e 100644 --- a/net/quic/core/crypto/null_encrypter.h +++ b/net/quic/core/crypto/null_encrypter.h
@@ -27,7 +27,6 @@ bool SetKey(base::StringPiece key) override; bool SetNoncePrefix(base::StringPiece nonce_prefix) override; bool EncryptPacket(QuicVersion version, - QuicPathId path_id, QuicPacketNumber packet_number, base::StringPiece associated_data, base::StringPiece plaintext,
diff --git a/net/quic/core/crypto/null_encrypter_test.cc b/net/quic/core/crypto/null_encrypter_test.cc index e0296e4..d875e0e 100644 --- a/net/quic/core/crypto/null_encrypter_test.cc +++ b/net/quic/core/crypto/null_encrypter_test.cc
@@ -22,9 +22,9 @@ char encrypted[256]; size_t encrypted_len = 0; NullEncrypter encrypter(Perspective::IS_CLIENT); - ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_37, kDefaultPathId, 0, - "hello world!", "goodbye!", encrypted, - &encrypted_len, 256)); + ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_37, 0, "hello world!", + "goodbye!", encrypted, &encrypted_len, + 256)); test::CompareCharArraysWithHexError( "encrypted data", encrypted, encrypted_len, reinterpret_cast<const char*>(expected), arraysize(expected)); @@ -40,9 +40,9 @@ char encrypted[256]; size_t encrypted_len = 0; NullEncrypter encrypter(Perspective::IS_SERVER); - ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_37, kDefaultPathId, 0, - "hello world!", "goodbye!", encrypted, - &encrypted_len, 256)); + ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_37, 0, "hello world!", + "goodbye!", encrypted, &encrypted_len, + 256)); test::CompareCharArraysWithHexError( "encrypted data", encrypted, encrypted_len, reinterpret_cast<const char*>(expected), arraysize(expected)); @@ -58,9 +58,9 @@ char encrypted[256]; size_t encrypted_len = 0; NullEncrypter encrypter(Perspective::IS_CLIENT); - ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_36, kDefaultPathId, 0, - "hello world!", "goodbye!", encrypted, - &encrypted_len, 256)); + ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_36, 0, "hello world!", + "goodbye!", encrypted, &encrypted_len, + 256)); test::CompareCharArraysWithHexError( "encrypted data", encrypted, encrypted_len, reinterpret_cast<const char*>(expected), arraysize(expected)); @@ -76,9 +76,9 @@ char encrypted[256]; size_t encrypted_len = 0; NullEncrypter encrypter(Perspective::IS_SERVER); - ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_36, kDefaultPathId, 0, - "hello world!", "goodbye!", encrypted, - &encrypted_len, 256)); + ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_36, 0, "hello world!", + "goodbye!", encrypted, &encrypted_len, + 256)); test::CompareCharArraysWithHexError( "encrypted data", encrypted, encrypted_len, reinterpret_cast<const char*>(expected), arraysize(expected));
diff --git a/net/quic/core/crypto/proof_source.h b/net/quic/core/crypto/proof_source.h index 8fd184f..a8d7f0a 100644 --- a/net/quic/core/crypto/proof_source.h +++ b/net/quic/core/crypto/proof_source.h
@@ -75,9 +75,8 @@ virtual ~ProofSource() {} - // GetProof finds a certificate chain for |hostname|, sets |out_chain| to - // point to it (in leaf-first order), calculates a signature of - // |server_config| using that chain and puts the result in |out_signature|. + // GetProof finds a certificate chain for |hostname| (in leaf-first order), + // and calculates a signature of |server_config| using that chain. // // The signature uses SHA-256 as the hash function and PSS padding when the // key is RSA. @@ -85,36 +84,15 @@ // The signature uses SHA-256 as the hash function when the key is ECDSA. // The signature may use an ECDSA key. // - // |out_chain| is reference counted to avoid the (assumed) expense of copying - // out the certificates. - // - // The number of certificate chains is expected to be small and fixed, thus - // the ProofSource retains ownership of the contents of |out_chain|. The - // expectation is that they will be cached forever. - // // The signature depends on |chlo_hash| which means that the signature can not - // be cached. The caller takes ownership of |*out_signature|. + // be cached. // // |hostname| may be empty to signify that a default certificate should be // used. // - // |out_leaf_cert_sct| points to the signed timestamp (RFC6962) of the leaf - // cert. - // // This function may be called concurrently. - virtual bool GetProof(const QuicSocketAddress& server_address, - const std::string& hostname, - const std::string& server_config, - QuicVersion quic_version, - base::StringPiece chlo_hash, - const QuicTagVector& connection_options, - QuicReferenceCountedPointer<Chain>* out_chain, - QuicCryptoProof* out_proof) = 0; - - // Async version of GetProof with identical semantics, except that the results - // are delivered to |callback|. Callers should expect that |callback| might - // be invoked synchronously. The ProofSource takes ownership of |callback| in - // any case. + // + // Callers should expect that |callback| might be invoked synchronously. virtual void GetProof(const QuicSocketAddress& server_address, const std::string& hostname, const std::string& server_config,
diff --git a/net/quic/core/crypto/quic_crypto_client_config.cc b/net/quic/core/crypto/quic_crypto_client_config.cc index cc7232e..6835bed9 100644 --- a/net/quic/core/crypto/quic_crypto_client_config.cc +++ b/net/quic/core/crypto/quic_crypto_client_config.cc
@@ -658,10 +658,9 @@ std::unique_ptr<char[]> output(new char[encrypted_len]); size_t output_size = 0; if (!crypters.encrypter->EncryptPacket( - preferred_version, kDefaultPathId /* path id */, - 0 /* packet number */, StringPiece() /* associated data */, - cetv_plaintext.AsStringPiece(), output.get(), &output_size, - encrypted_len)) { + preferred_version, 0 /* packet number */, + StringPiece() /* associated data */, cetv_plaintext.AsStringPiece(), + output.get(), &output_size, encrypted_len)) { *error_details = "Packet encryption failed"; return QUIC_ENCRYPTION_FAILURE; }
diff --git a/net/quic/core/crypto/quic_crypto_client_config_test.cc b/net/quic/core/crypto/quic_crypto_client_config_test.cc index 5d15437..68bae7d 100644 --- a/net/quic/core/crypto/quic_crypto_client_config_test.cc +++ b/net/quic/core/crypto/quic_crypto_client_config_test.cc
@@ -168,7 +168,7 @@ TEST(QuicCryptoClientConfigTest, InchoateChlo) { QuicCryptoClientConfig::CachedState state; - QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params( new QuicCryptoNegotiatedParameters); CryptoHandshakeMessage msg; @@ -186,7 +186,7 @@ } TEST(QuicCryptoClientConfigTest, PreferAesGcm) { - QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); if (config.aead.size() > 1) EXPECT_NE(kAESG, config.aead[0]); config.PreferAesGcm(); @@ -195,7 +195,7 @@ TEST(QuicCryptoClientConfigTest, InchoateChloSecure) { QuicCryptoClientConfig::CachedState state; - QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params( new QuicCryptoNegotiatedParameters); CryptoHandshakeMessage msg; @@ -224,7 +224,7 @@ state.SetServerConfig(scfg.GetSerialized().AsStringPiece(), now, expiry, &details); - QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params( new QuicCryptoNegotiatedParameters); CryptoHandshakeMessage msg; @@ -250,7 +250,7 @@ QuicWallTime::FromUNIXSeconds(1), QuicWallTime::FromUNIXSeconds(0), &details); - QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params( new QuicCryptoNegotiatedParameters); CryptoHandshakeMessage msg; @@ -266,7 +266,7 @@ TEST(QuicCryptoClientConfigTest, FillClientHello) { QuicCryptoClientConfig::CachedState state; - QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params( new QuicCryptoNegotiatedParameters); QuicConnectionId kConnectionId = 1234; @@ -304,7 +304,7 @@ QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params( new QuicCryptoNegotiatedParameters); string error; - QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); EXPECT_EQ(QUIC_VERSION_NEGOTIATION_MISMATCH, config.ProcessServerHello(msg, 0, supported_versions.front(), supported_versions, &cached, out_params, @@ -313,7 +313,7 @@ } TEST(QuicCryptoClientConfigTest, InitializeFrom) { - QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); QuicServerId canonical_server_id("www.google.com", 443, PRIVACY_MODE_DISABLED); QuicCryptoClientConfig::CachedState* state = @@ -334,7 +334,7 @@ } TEST(QuicCryptoClientConfigTest, Canonical) { - QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); config.AddCanonicalSuffix(".google.com"); QuicServerId canonical_id1("www.google.com", 443, PRIVACY_MODE_DISABLED); QuicServerId canonical_id2("mail.google.com", 443, PRIVACY_MODE_DISABLED); @@ -358,7 +358,7 @@ } TEST(QuicCryptoClientConfigTest, CanonicalNotUsedIfNotValid) { - QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); config.AddCanonicalSuffix(".google.com"); QuicServerId canonical_id1("www.google.com", 443, PRIVACY_MODE_DISABLED); QuicServerId canonical_id2("mail.google.com", 443, PRIVACY_MODE_DISABLED); @@ -373,7 +373,7 @@ } TEST(QuicCryptoClientConfigTest, ClearCachedStates) { - QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); // Create two states on different origins. struct TestCase { @@ -461,14 +461,14 @@ TEST(QuicCryptoClientConfigTest, ProcessReject) { CryptoHandshakeMessage rej; - CryptoTestUtils::FillInDummyReject(&rej, /* stateless */ false); + crypto_test_utils::FillInDummyReject(&rej, /* stateless */ false); // Now process the rejection. QuicCryptoClientConfig::CachedState cached; QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params( new QuicCryptoNegotiatedParameters); string error; - QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); EXPECT_EQ(QUIC_NO_ERROR, config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0), AllSupportedVersions().front(), "", &cached, @@ -479,7 +479,7 @@ TEST(QuicCryptoClientConfigTest, ProcessRejectWithLongTTL) { CryptoHandshakeMessage rej; - CryptoTestUtils::FillInDummyReject(&rej, /* stateless */ false); + crypto_test_utils::FillInDummyReject(&rej, /* stateless */ false); QuicTime::Delta one_week = QuicTime::Delta::FromSeconds(kNumSecondsPerWeek); int64_t long_ttl = 3 * one_week.ToSeconds(); rej.SetValue(kSTTL, long_ttl); @@ -489,7 +489,7 @@ QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params( new QuicCryptoNegotiatedParameters); string error; - QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); EXPECT_EQ(QUIC_NO_ERROR, config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0), AllSupportedVersions().front(), "", &cached, @@ -505,7 +505,7 @@ TEST(QuicCryptoClientConfigTest, ProcessStatelessReject) { // Create a dummy reject message and mark it as stateless. CryptoHandshakeMessage rej; - CryptoTestUtils::FillInDummyReject(&rej, /* stateless */ true); + crypto_test_utils::FillInDummyReject(&rej, /* stateless */ true); const QuicConnectionId kConnectionId = 0xdeadbeef; const string server_nonce = "SERVER_NONCE"; rej.SetValue(kRCID, kConnectionId); @@ -516,7 +516,7 @@ QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params( new QuicCryptoNegotiatedParameters); string error; - QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); EXPECT_EQ(QUIC_NO_ERROR, config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0), AllSupportedVersions().front(), "", &cached, @@ -530,14 +530,14 @@ // Create a dummy reject message and mark it as stateless. Do not // add an server-designated connection-id. CryptoHandshakeMessage rej; - CryptoTestUtils::FillInDummyReject(&rej, /* stateless */ true); + crypto_test_utils::FillInDummyReject(&rej, /* stateless */ true); // Now process the rejection. QuicCryptoClientConfig::CachedState cached; QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params( new QuicCryptoNegotiatedParameters); string error; - QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0), AllSupportedVersions().front(), "", &cached, @@ -558,7 +558,7 @@ versions.push_back(QuicVersionToQuicTag(version)); msg.SetVector(kVER, versions); - QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting()); + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting()); QuicCryptoClientConfig::CachedState cached; QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params( new QuicCryptoNegotiatedParameters);
diff --git a/net/quic/core/crypto/quic_crypto_server_config.cc b/net/quic/core/crypto/quic_crypto_server_config.cc index 4e6f0310..43a752a7 100644 --- a/net/quic/core/crypto/quic_crypto_server_config.cc +++ b/net/quic/core/crypto/quic_crypto_server_config.cc
@@ -11,7 +11,6 @@ #include "base/macros.h" #include "crypto/hkdf.h" -#include "crypto/secure_hash.h" #include "net/quic/core/crypto/aes_128_gcm_12_decrypter.h" #include "net/quic/core/crypto/aes_128_gcm_12_encrypter.h" #include "net/quic/core/crypto/cert_compressor.h" @@ -40,6 +39,7 @@ #include "net/quic/platform/api/quic_reference_counted.h" #include "net/quic/platform/api/quic_text_utils.h" #include "net/quic/platform/api/quic_url_utils.h" +#include "third_party/boringssl/src/include/openssl/sha.h" using base::StringPiece; using std::string; @@ -66,8 +66,6 @@ } // namespace -using crypto::SecureHash; - class ValidateClientHelloHelper { public: // Note: stores a pointer to a unique_ptr, and std::moves the unique_ptr when @@ -264,12 +262,14 @@ // thus we make it a hash of the rest of the server config. std::unique_ptr<QuicData> serialized( CryptoFramer::ConstructHandshakeMessage(msg)); - std::unique_ptr<SecureHash> hash(SecureHash::Create(SecureHash::SHA256)); - hash->Update(serialized->data(), serialized->length()); - char scid_bytes[16]; - hash->Finish(scid_bytes, sizeof(scid_bytes)); - msg.SetStringPiece(kSCID, StringPiece(scid_bytes, sizeof(scid_bytes))); + uint8_t scid_bytes[SHA256_DIGEST_LENGTH]; + SHA256(reinterpret_cast<const uint8_t*>(serialized->data()), + serialized->length(), scid_bytes); + // The SCID is a truncated SHA-256 digest. + static_assert(16 <= SHA256_DIGEST_LENGTH, "SCID length too high."); + msg.SetStringPiece( + kSCID, StringPiece(reinterpret_cast<const char*>(scid_bytes), 16)); } else { msg.SetStringPiece(kSCID, options.id); } @@ -698,31 +698,19 @@ if (client_hello.GetTaglist(kCOPT, &tag_ptr, &num_tags) == QUIC_NO_ERROR) { connection_options.assign(tag_ptr, tag_ptr + num_tags); } - if (FLAGS_quic_reloadable_flag_enable_async_get_proof) { - std::unique_ptr<ProcessClientHelloCallback> cb( - new ProcessClientHelloCallback( - this, validate_chlo_result, reject_only, connection_id, - client_address, version, supported_versions, - use_stateless_rejects, server_designated_connection_id, clock, - rand, compressed_certs_cache, params, signed_config, - total_framing_overhead, chlo_packet_size, requested_config, - primary_config, std::move(done_cb))); - proof_source_->GetProof(server_address, info.sni.as_string(), - primary_config->serialized, version, chlo_hash, - connection_options, std::move(cb)); - helper.DetachCallback(); - return; - } - - QuicCryptoProof proof; - if (!proof_source_->GetProof(server_address, info.sni.as_string(), - primary_config->serialized, version, chlo_hash, - connection_options, &signed_config->chain, - &proof)) { - helper.Fail(QUIC_HANDSHAKE_FAILED, "Missing or invalid crypto proof."); - return; - } - signed_config->proof = proof; + std::unique_ptr<ProcessClientHelloCallback> cb( + new ProcessClientHelloCallback( + this, validate_chlo_result, reject_only, connection_id, + client_address, version, supported_versions, use_stateless_rejects, + server_designated_connection_id, clock, rand, + compressed_certs_cache, params, signed_config, + total_framing_overhead, chlo_packet_size, requested_config, + primary_config, std::move(done_cb))); + proof_source_->GetProof(server_address, info.sni.as_string(), + primary_config->serialized, version, chlo_hash, + connection_options, std::move(cb)); + helper.DetachCallback(); + return; } helper.DetachCallback(); @@ -907,7 +895,7 @@ char plaintext[kMaxPacketSize]; size_t plaintext_length = 0; const bool success = crypters.decrypter->DecryptPacket( - QUIC_VERSION_35, kDefaultPathId, 0 /* packet number */, + QUIC_VERSION_35, 0 /* packet number */, StringPiece() /* associated data */, cetv_ciphertext, plaintext, &plaintext_length, kMaxPacketSize); if (!success) { @@ -1275,34 +1263,20 @@ if (client_hello.GetTaglist(kCOPT, &tag_ptr, &num_tags) == QUIC_NO_ERROR) { connection_options.assign(tag_ptr, tag_ptr + num_tags); } - if (FLAGS_quic_reloadable_flag_enable_async_get_proof) { - if (need_proof) { - // Make an async call to GetProof and setup the callback to trampoline - // back into EvaluateClientHelloAfterGetProof - std::unique_ptr<EvaluateClientHelloCallback> cb( - new EvaluateClientHelloCallback( - *this, found_error, server_address.host(), version, - requested_config, primary_config, signed_config, - client_hello_state, std::move(done_cb))); - proof_source_->GetProof(server_address, info->sni.as_string(), - serialized_config, version, chlo_hash, - connection_options, std::move(cb)); - helper.DetachCallback(); - return; - } - } - // No need to get a new proof if one was already generated. if (need_proof) { - QuicCryptoProof proof; - - if (proof_source_->GetProof( - server_address, info->sni.as_string(), serialized_config, version, - chlo_hash, connection_options, &signed_config->chain, &proof)) { - signed_config->proof = proof; - } else { - get_proof_failed = true; - } + // Make an async call to GetProof and setup the callback to trampoline + // back into EvaluateClientHelloAfterGetProof + std::unique_ptr<EvaluateClientHelloCallback> cb( + new EvaluateClientHelloCallback( + *this, found_error, server_address.host(), version, + requested_config, primary_config, signed_config, client_hello_state, + std::move(done_cb))); + proof_source_->GetProof(server_address, info->sni.as_string(), + serialized_config, version, chlo_hash, + connection_options, std::move(cb)); + helper.DetachCallback(); + return; } // Details are null because the synchronous version of GetProof does not @@ -1361,65 +1335,6 @@ helper.ValidationComplete(QUIC_NO_ERROR, "", std::move(proof_source_details)); } -bool QuicCryptoServerConfig::BuildServerConfigUpdateMessage( - QuicVersion version, - StringPiece chlo_hash, - const SourceAddressTokens& previous_source_address_tokens, - const QuicSocketAddress& server_address, - const QuicIpAddress& client_ip, - const QuicClock* clock, - QuicRandom* rand, - QuicCompressedCertsCache* compressed_certs_cache, - const QuicCryptoNegotiatedParameters& params, - const CachedNetworkParameters* cached_network_params, - const QuicTagVector& connection_options, - CryptoHandshakeMessage* out) const { - string serialized; - string source_address_token; - QuicWallTime expiry_time = QuicWallTime::Zero(); - const CommonCertSets* common_cert_sets; - { - QuicReaderMutexLock locked(&configs_lock_); - serialized = primary_config_->serialized; - common_cert_sets = primary_config_->common_cert_sets; - expiry_time = primary_config_->expiry_time; - source_address_token = NewSourceAddressToken( - *primary_config_, previous_source_address_tokens, client_ip, rand, - clock->WallNow(), cached_network_params); - } - - out->set_tag(kSCUP); - out->SetStringPiece(kSCFG, serialized); - out->SetStringPiece(kSourceAddressTokenTag, source_address_token); - out->SetValue(kSTTL, - expiry_time.AbsoluteDifference(clock->WallNow()).ToSeconds()); - - QuicReferenceCountedPointer<ProofSource::Chain> chain; - QuicCryptoProof proof; - if (!proof_source_->GetProof(server_address, params.sni, serialized, version, - chlo_hash, connection_options, &chain, &proof)) { - QUIC_DVLOG(1) << "Server: failed to get proof."; - return false; - } - - const string compressed = CompressChain( - compressed_certs_cache, chain, params.client_common_set_hashes, - params.client_cached_cert_hashes, common_cert_sets); - - out->SetStringPiece(kCertificateTag, compressed); - out->SetStringPiece(kPROF, proof.signature); - if (params.sct_supported_by_client && enable_serving_sct_) { - if (proof.leaf_cert_scts.empty()) { - QUIC_LOG_EVERY_N_SEC(WARNING, 60) - << "SCT is expected but it is empty. sni: " << params.sni - << " server_address: " << server_address.ToString(); - } else { - out->SetStringPiece(kCertificateSCTTag, proof.leaf_cert_scts); - } - } - return true; -} - void QuicCryptoServerConfig::BuildServerConfigUpdateMessage( QuicVersion version, StringPiece chlo_hash,
diff --git a/net/quic/core/crypto/quic_crypto_server_config.h b/net/quic/core/crypto/quic_crypto_server_config.h index 42e9e2e..358f6afa 100644 --- a/net/quic/core/crypto/quic_crypto_server_config.h +++ b/net/quic/core/crypto/quic_crypto_server_config.h
@@ -327,29 +327,6 @@ QuicByteCount chlo_packet_size, std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const; - // BuildServerConfigUpdateMessage sets |out| to be a SCUP message containing - // the current primary config, an up to date source-address token, and cert - // chain and proof in the case of secure QUIC. Returns true if successfully - // filled |out|. - // - // |cached_network_params| is optional, and can be nullptr. - // - // TODO(gredner): remove this when - // FLAGS_quic_reloadable_flag_enable_async_get_proof is removed. - bool BuildServerConfigUpdateMessage( - QuicVersion version, - base::StringPiece chlo_hash, - const SourceAddressTokens& previous_source_address_tokens, - const QuicSocketAddress& server_address, - const QuicIpAddress& client_ip, - const QuicClock* clock, - QuicRandom* rand, - QuicCompressedCertsCache* compressed_certs_cache, - const QuicCryptoNegotiatedParameters& params, - const CachedNetworkParameters* cached_network_params, - const QuicTagVector& connection_options, - CryptoHandshakeMessage* out) const; - // BuildServerConfigUpdateMessage invokes |cb| with a SCUP message containing // the current primary config, an up to date source-address token, and cert // chain and proof in the case of secure QUIC. Passes true to |cb| if the @@ -357,9 +334,6 @@ // assumes ownership of |cb|. // // |cached_network_params| is optional, and can be nullptr. - // - // TODO(gredner): This method is an async version of the above. The - // synchronous version will eventually be removed. void BuildServerConfigUpdateMessage( QuicVersion version, base::StringPiece chlo_hash,
diff --git a/net/quic/core/crypto/quic_crypto_server_config_test.cc b/net/quic/core/crypto/quic_crypto_server_config_test.cc index da7f858..c002e57 100644 --- a/net/quic/core/crypto/quic_crypto_server_config_test.cc +++ b/net/quic/core/crypto/quic_crypto_server_config_test.cc
@@ -30,7 +30,7 @@ TEST(QuicCryptoServerConfigTest, ServerConfig) { QuicRandom* rand = QuicRandom::GetInstance(); QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand, - CryptoTestUtils::ProofSourceForTesting()); + crypto_test_utils::ProofSourceForTesting()); MockClock clock; std::unique_ptr<CryptoHandshakeMessage> message(server.AddDefaultConfig( @@ -52,7 +52,7 @@ QuicRandom* rand = QuicRandom::GetInstance(); QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand, - CryptoTestUtils::ProofSourceForTesting()); + crypto_test_utils::ProofSourceForTesting()); QuicCryptoServerConfigPeer peer(&server); std::vector<string> certs = {"testcert"}; @@ -71,7 +71,7 @@ QuicRandom* rand = QuicRandom::GetInstance(); QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand, - CryptoTestUtils::ProofSourceForTesting()); + crypto_test_utils::ProofSourceForTesting()); QuicCryptoServerConfigPeer peer(&server); // Compress the certs for the first time. @@ -100,7 +100,7 @@ QuicRandom* rand = QuicRandom::GetInstance(); QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand, - CryptoTestUtils::ProofSourceForTesting()); + crypto_test_utils::ProofSourceForTesting()); QuicCryptoServerConfigPeer peer(&server); std::vector<string> certs = {"testcert"}; @@ -124,7 +124,7 @@ // Compress a similar certs which only differs in common certs field. static const uint64_t set_hash = 42; std::unique_ptr<CommonCertSets> common_sets( - CryptoTestUtils::MockCommonCertSets(certs[0], set_hash, 1)); + crypto_test_utils::MockCommonCertSets(certs[0], set_hash, 1)); StringPiece different_common_certs(reinterpret_cast<const char*>(&set_hash), sizeof(set_hash)); string compressed3 = QuicCryptoServerConfigPeer::CompressChain( @@ -143,7 +143,7 @@ rand_(QuicRandom::GetInstance()), server_(QuicCryptoServerConfig::TESTING, rand_, - CryptoTestUtils::ProofSourceForTesting()), + crypto_test_utils::ProofSourceForTesting()), peer_(&server_) { // Advance the clock to some non-zero time. clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1000000)); @@ -281,7 +281,7 @@ : rand_(QuicRandom::GetInstance()), config_(QuicCryptoServerConfig::TESTING, rand_, - CryptoTestUtils::ProofSourceForTesting()), + crypto_test_utils::ProofSourceForTesting()), test_peer_(&config_) {} void SetUp() override { @@ -289,49 +289,42 @@ } // SetConfigs constructs suitable config protobufs and calls SetConfigs on - // |config_|. The arguments are given as nullptr-terminated pairs. The first - // of each pair is the server config ID of a Config. The second is the - // |primary_time| of that Config, given in epoch seconds. (Although note that, - // in these tests, time is set to 1000 seconds since the epoch.) For example: - // SetConfigs(nullptr); // calls |config_.SetConfigs| with no protobufs. + // |config_|. + // Each struct in the input vector contains 3 elements. + // The first is the server config ID of a Config. The second is + // the |primary_time| of that Config, given in epoch seconds. (Although note + // that, in these tests, time is set to 1000 seconds since the epoch.). + // The third is the priority. + // + // For example: + // SetConfigs(std::vector<ServerConfigIDWithTimeAndPriority>()); // calls + // |config_.SetConfigs| with no protobufs. // // // Calls |config_.SetConfigs| with two protobufs: one for a Config with // // a |primary_time| of 900 and priority 1, and another with // // a |primary_time| of 1000 and priority 2. // CheckConfigs( - // "id1", 900, 1, - // "id2", 1000, 2, - // nullptr); + // {{"id1", 900, 1}, + // {"id2", 1000, 2}}); // // If the server config id starts with "INVALID" then the generated protobuf // will be invalid. - void SetConfigs(const char* server_config_id1, ...) { + struct ServerConfigIDWithTimeAndPriority { + ServerConfigID server_config_id; + int primary_time; + int priority; + }; + void SetConfigs(std::vector<ServerConfigIDWithTimeAndPriority> configs) { const char kOrbit[] = "12345678"; - va_list ap; - va_start(ap, server_config_id1); bool has_invalid = false; - bool is_empty = true; std::vector<std::unique_ptr<QuicServerConfigProtobuf>> protobufs; - bool first = true; - for (;;) { - const char* server_config_id; - if (first) { - server_config_id = server_config_id1; - first = false; - } else { - server_config_id = va_arg(ap, const char*); - } - - if (!server_config_id) { - break; - } - - is_empty = false; - int primary_time = va_arg(ap, int); - int priority = va_arg(ap, int); + for (const auto& config : configs) { + const ServerConfigID& server_config_id = config.server_config_id; + const int primary_time = config.primary_time; + const int priority = config.priority; QuicCryptoServerConfig::ConfigOptions options; options.id = server_config_id; @@ -347,7 +340,7 @@ protobufs.push_back(std::move(protobuf)); } - ASSERT_EQ(!has_invalid && !is_empty, + ASSERT_EQ(!has_invalid && !configs.empty(), config_.SetConfigs(protobufs, clock_.WallNow())); } @@ -359,104 +352,104 @@ }; TEST_F(CryptoServerConfigsTest, NoConfigs) { - test_peer_.CheckConfigs(nullptr); + test_peer_.CheckConfigs(std::vector<std::pair<string, bool>>()); } TEST_F(CryptoServerConfigsTest, MakePrimaryFirst) { // Make sure that "b" is primary even though "a" comes first. - SetConfigs("a", 1100, 1, "b", 900, 1, nullptr); - test_peer_.CheckConfigs("a", false, "b", true, nullptr); + SetConfigs({{"a", 1100, 1}, {"b", 900, 1}}); + test_peer_.CheckConfigs({{"a", false}, {"b", true}}); } TEST_F(CryptoServerConfigsTest, MakePrimarySecond) { // Make sure that a remains primary after b is added. - SetConfigs("a", 900, 1, "b", 1100, 1, nullptr); - test_peer_.CheckConfigs("a", true, "b", false, nullptr); + SetConfigs({{"a", 900, 1}, {"b", 1100, 1}}); + test_peer_.CheckConfigs({{"a", true}, {"b", false}}); } TEST_F(CryptoServerConfigsTest, Delete) { // Ensure that configs get deleted when removed. - SetConfigs("a", 800, 1, "b", 900, 1, "c", 1100, 1, nullptr); - test_peer_.CheckConfigs("a", false, "b", true, "c", false, nullptr); - SetConfigs("b", 900, 1, "c", 1100, 1, nullptr); - test_peer_.CheckConfigs("b", true, "c", false, nullptr); + SetConfigs({{"a", 800, 1}, {"b", 900, 1}, {"c", 1100, 1}}); + test_peer_.CheckConfigs({{"a", false}, {"b", true}, {"c", false}}); + SetConfigs({{"b", 900, 1}, {"c", 1100, 1}}); + test_peer_.CheckConfigs({{"b", true}, {"c", false}}); } TEST_F(CryptoServerConfigsTest, DeletePrimary) { // Ensure that deleting the primary config works. - SetConfigs("a", 800, 1, "b", 900, 1, "c", 1100, 1, nullptr); - test_peer_.CheckConfigs("a", false, "b", true, "c", false, nullptr); - SetConfigs("a", 800, 1, "c", 1100, 1, nullptr); - test_peer_.CheckConfigs("a", true, "c", false, nullptr); + SetConfigs({{"a", 800, 1}, {"b", 900, 1}, {"c", 1100, 1}}); + test_peer_.CheckConfigs({{"a", false}, {"b", true}, {"c", false}}); + SetConfigs({{"a", 800, 1}, {"c", 1100, 1}}); + test_peer_.CheckConfigs({{"a", true}, {"c", false}}); } TEST_F(CryptoServerConfigsTest, FailIfDeletingAllConfigs) { // Ensure that configs get deleted when removed. - SetConfigs("a", 800, 1, "b", 900, 1, nullptr); - test_peer_.CheckConfigs("a", false, "b", true, nullptr); - SetConfigs(nullptr); + SetConfigs({{"a", 800, 1}, {"b", 900, 1}}); + test_peer_.CheckConfigs({{"a", false}, {"b", true}}); + SetConfigs(std::vector<ServerConfigIDWithTimeAndPriority>()); // Config change is rejected, still using old configs. - test_peer_.CheckConfigs("a", false, "b", true, nullptr); + test_peer_.CheckConfigs({{"a", false}, {"b", true}}); } TEST_F(CryptoServerConfigsTest, ChangePrimaryTime) { // Check that updates to primary time get picked up. - SetConfigs("a", 400, 1, "b", 800, 1, "c", 1200, 1, nullptr); + SetConfigs({{"a", 400, 1}, {"b", 800, 1}, {"c", 1200, 1}}); test_peer_.SelectNewPrimaryConfig(500); - test_peer_.CheckConfigs("a", true, "b", false, "c", false, nullptr); - SetConfigs("a", 1200, 1, "b", 800, 1, "c", 400, 1, nullptr); + test_peer_.CheckConfigs({{"a", true}, {"b", false}, {"c", false}}); + SetConfigs({{"a", 1200, 1}, {"b", 800, 1}, {"c", 400, 1}}); test_peer_.SelectNewPrimaryConfig(500); - test_peer_.CheckConfigs("a", false, "b", false, "c", true, nullptr); + test_peer_.CheckConfigs({{"a", false}, {"b", false}, {"c", true}}); } TEST_F(CryptoServerConfigsTest, AllConfigsInThePast) { // Check that the most recent config is selected. - SetConfigs("a", 400, 1, "b", 800, 1, "c", 1200, 1, nullptr); + SetConfigs({{"a", 400, 1}, {"b", 800, 1}, {"c", 1200, 1}}); test_peer_.SelectNewPrimaryConfig(1500); - test_peer_.CheckConfigs("a", false, "b", false, "c", true, nullptr); + test_peer_.CheckConfigs({{"a", false}, {"b", false}, {"c", true}}); } TEST_F(CryptoServerConfigsTest, AllConfigsInTheFuture) { // Check that the first config is selected. - SetConfigs("a", 400, 1, "b", 800, 1, "c", 1200, 1, nullptr); + SetConfigs({{"a", 400, 1}, {"b", 800, 1}, {"c", 1200, 1}}); test_peer_.SelectNewPrimaryConfig(100); - test_peer_.CheckConfigs("a", true, "b", false, "c", false, nullptr); + test_peer_.CheckConfigs({{"a", true}, {"b", false}, {"c", false}}); } TEST_F(CryptoServerConfigsTest, SortByPriority) { // Check that priority is used to decide on a primary config when // configs have the same primary time. - SetConfigs("a", 900, 1, "b", 900, 2, "c", 900, 3, nullptr); - test_peer_.CheckConfigs("a", true, "b", false, "c", false, nullptr); + SetConfigs({{"a", 900, 1}, {"b", 900, 2}, {"c", 900, 3}}); + test_peer_.CheckConfigs({{"a", true}, {"b", false}, {"c", false}}); test_peer_.SelectNewPrimaryConfig(800); - test_peer_.CheckConfigs("a", true, "b", false, "c", false, nullptr); + test_peer_.CheckConfigs({{"a", true}, {"b", false}, {"c", false}}); test_peer_.SelectNewPrimaryConfig(1000); - test_peer_.CheckConfigs("a", true, "b", false, "c", false, nullptr); + test_peer_.CheckConfigs({{"a", true}, {"b", false}, {"c", false}}); // Change priorities and expect sort order to change. - SetConfigs("a", 900, 2, "b", 900, 1, "c", 900, 0, nullptr); - test_peer_.CheckConfigs("a", false, "b", false, "c", true, nullptr); + SetConfigs({{"a", 900, 2}, {"b", 900, 1}, {"c", 900, 0}}); + test_peer_.CheckConfigs({{"a", false}, {"b", false}, {"c", true}}); test_peer_.SelectNewPrimaryConfig(800); - test_peer_.CheckConfigs("a", false, "b", false, "c", true, nullptr); + test_peer_.CheckConfigs({{"a", false}, {"b", false}, {"c", true}}); test_peer_.SelectNewPrimaryConfig(1000); - test_peer_.CheckConfigs("a", false, "b", false, "c", true, nullptr); + test_peer_.CheckConfigs({{"a", false}, {"b", false}, {"c", true}}); } TEST_F(CryptoServerConfigsTest, AdvancePrimary) { // Check that a new primary config is enabled at the right time. - SetConfigs("a", 900, 1, "b", 1100, 1, nullptr); + SetConfigs({{"a", 900, 1}, {"b", 1100, 1}}); test_peer_.SelectNewPrimaryConfig(1000); - test_peer_.CheckConfigs("a", true, "b", false, nullptr); + test_peer_.CheckConfigs({{"a", true}, {"b", false}}); test_peer_.SelectNewPrimaryConfig(1101); - test_peer_.CheckConfigs("a", false, "b", true, nullptr); + test_peer_.CheckConfigs({{"a", false}, {"b", true}}); } TEST_F(CryptoServerConfigsTest, InvalidConfigs) { // Ensure that invalid configs don't change anything. - SetConfigs("a", 800, 1, "b", 900, 1, "c", 1100, 1, nullptr); - test_peer_.CheckConfigs("a", false, "b", true, "c", false, nullptr); - SetConfigs("a", 800, 1, "c", 1100, 1, "INVALID1", 1000, 1, nullptr); - test_peer_.CheckConfigs("a", false, "b", true, "c", false, nullptr); + SetConfigs({{"a", 800, 1}, {"b", 900, 1}, {"c", 1100, 1}}); + test_peer_.CheckConfigs({{"a", false}, {"b", true}, {"c", false}}); + SetConfigs({{"a", 800, 1}, {"c", 1100, 1}, {"INVALID1", 1000, 1}}); + test_peer_.CheckConfigs({{"a", false}, {"b", true}, {"c", false}}); } } // namespace test
diff --git a/net/quic/core/crypto/quic_decrypter.h b/net/quic/core/crypto/quic_decrypter.h index 824cf92..a47643ea 100644 --- a/net/quic/core/crypto/quic_decrypter.h +++ b/net/quic/core/crypto/quic_decrypter.h
@@ -67,7 +67,6 @@ // TODO(wtc): add a way for DecryptPacket to report decryption failure due // to non-authentic inputs, as opposed to other reasons for failure. virtual bool DecryptPacket(QuicVersion version, - QuicPathId path_id, QuicPacketNumber packet_number, base::StringPiece associated_data, base::StringPiece ciphertext,
diff --git a/net/quic/core/crypto/quic_encrypter.h b/net/quic/core/crypto/quic_encrypter.h index 67398672..40d079c 100644 --- a/net/quic/core/crypto/quic_encrypter.h +++ b/net/quic/core/crypto/quic_encrypter.h
@@ -49,7 +49,6 @@ // |associated_data|. If |output| overlaps with |plaintext| then // |plaintext| must be <= |output|. virtual bool EncryptPacket(QuicVersion version, - QuicPathId path_id, QuicPacketNumber packet_number, base::StringPiece associated_data, base::StringPiece plaintext,
diff --git a/net/quic/core/quic_client_promised_info_test.cc b/net/quic/core/quic_client_promised_info_test.cc index 4535720..f950390 100644 --- a/net/quic/core/quic_client_promised_info_test.cc +++ b/net/quic/core/quic_client_promised_info_test.cc
@@ -32,7 +32,7 @@ QuicServerId("example.com", 443, PRIVACY_MODE_DISABLED), &crypto_config_, push_promise_index), - crypto_config_(CryptoTestUtils::ProofVerifierForTesting()), + crypto_config_(crypto_test_utils::ProofVerifierForTesting()), authorized_(true) {} ~MockQuicClientSession() override {}
diff --git a/net/quic/core/quic_client_push_promise_index_test.cc b/net/quic/core/quic_client_push_promise_index_test.cc index 73407c5..cdc0902 100644 --- a/net/quic/core/quic_client_push_promise_index_test.cc +++ b/net/quic/core/quic_client_push_promise_index_test.cc
@@ -31,7 +31,7 @@ QuicServerId("example.com", 443, PRIVACY_MODE_DISABLED), &crypto_config_, push_promise_index), - crypto_config_(CryptoTestUtils::ProofVerifierForTesting()) {} + crypto_config_(crypto_test_utils::ProofVerifierForTesting()) {} ~MockQuicClientSession() override {} MOCK_METHOD1(CloseStream, void(QuicStreamId stream_id));
diff --git a/net/quic/core/quic_connection.cc b/net/quic/core/quic_connection.cc index 3bc93ab..56e8c33 100644 --- a/net/quic/core/quic_connection.cc +++ b/net/quic/core/quic_connection.cc
@@ -343,10 +343,7 @@ ack_decimation_delay_ = kShortAckDecimationDelay; } if (config.HasClientSentConnectionOption(k5RTO, perspective_)) { - if (perspective_ == Perspective::IS_CLIENT || - !FLAGS_quic_reloadable_flag_quic_only_5rto_client_side) { - close_connection_after_five_rtos_ = true; - } + close_connection_after_five_rtos_ = true; } }
diff --git a/net/quic/core/quic_connection_test.cc b/net/quic/core/quic_connection_test.cc index 906850fd..f19d61e1 100644 --- a/net/quic/core/quic_connection_test.cc +++ b/net/quic/core/quic_connection_test.cc
@@ -90,7 +90,6 @@ bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; } bool EncryptPacket(QuicVersion /*version*/, - QuicPathId path_id, QuicPacketNumber packet_number, StringPiece associated_data, StringPiece plaintext, @@ -155,7 +154,6 @@ } bool DecryptPacket(QuicVersion /*version*/, - QuicPathId path_id, QuicPacketNumber packet_number, StringPiece associated_data, StringPiece ciphertext, @@ -499,8 +497,7 @@ char buffer[kMaxPacketSize]; size_t encrypted_length = QuicConnectionPeer::GetFramer(this)->EncryptPayload( - ENCRYPTION_NONE, path_id, packet_number, *packet, buffer, - kMaxPacketSize); + ENCRYPTION_NONE, packet_number, *packet, buffer, kMaxPacketSize); delete packet; SerializedPacket serialized_packet( kDefaultPathId, packet_number, PACKET_6BYTE_PACKET_NUMBER, buffer, @@ -839,8 +836,8 @@ std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames)); char buffer[kMaxPacketSize]; - size_t encrypted_length = framer_.EncryptPayload( - level, path_id, number, *packet, buffer, kMaxPacketSize); + size_t encrypted_length = + framer_.EncryptPayload(level, number, *packet, buffer, kMaxPacketSize); connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false)); @@ -859,7 +856,7 @@ ConstructDataPacket(path_id, number, has_stop_waiting)); char buffer[kMaxPacketSize]; size_t encrypted_length = peer_framer_.EncryptPayload( - level, path_id, number, *packet, buffer, kMaxPacketSize); + level, number, *packet, buffer, kMaxPacketSize); connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, QuicReceivedPacket(buffer, encrypted_length, clock_.Now(), false)); @@ -873,7 +870,7 @@ std::unique_ptr<QuicPacket> packet(ConstructClosePacket(number)); char buffer[kMaxPacketSize]; size_t encrypted_length = peer_framer_.EncryptPayload( - ENCRYPTION_NONE, path_id, number, *packet, buffer, kMaxPacketSize); + ENCRYPTION_NONE, number, *packet, buffer, kMaxPacketSize); connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false)); @@ -1216,7 +1213,7 @@ std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames)); char buffer[kMaxPacketSize]; size_t encrypted_length = peer_framer_.EncryptPayload( - ENCRYPTION_NONE, kDefaultPathId, 12, *packet, buffer, kMaxPacketSize); + ENCRYPTION_NONE, 12, *packet, buffer, kMaxPacketSize); EXPECT_EQ(kMaxPacketSize, encrypted_length); framer_.set_version(version()); @@ -1250,7 +1247,7 @@ std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames)); char buffer[kMaxPacketSize]; size_t encrypted_length = peer_framer_.EncryptPayload( - ENCRYPTION_NONE, kDefaultPathId, 12, *packet, buffer, kMaxPacketSize); + ENCRYPTION_NONE, 12, *packet, buffer, kMaxPacketSize); EXPECT_EQ(kMaxPacketSize, encrypted_length); framer_.set_version(version()); @@ -2042,7 +2039,6 @@ // Ensure that if the only data in flight is non-retransmittable, the // retransmission alarm is not set. TEST_P(QuicConnectionTest, CancelRetransmissionAlarmAfterResetStream) { - FLAGS_quic_reloadable_flag_quic_more_conservative_retransmission_alarm = true; QuicStreamId stream_id = 2; QuicPacketNumber last_data_packet; SendStreamDataToPeer(stream_id, "foo", 0, !kFin, &last_data_packet); @@ -2287,9 +2283,7 @@ writer_->SetWritable(); connection_.OnCanWrite(); // There is now a pending packet, but with no retransmittable frames. - EXPECT_EQ( - FLAGS_quic_reloadable_flag_quic_more_conservative_retransmission_alarm, - !connection_.GetRetransmissionAlarm()->IsSet()); + EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); EXPECT_FALSE(QuicConnectionPeer::HasRetransmittableFrames(&connection_, ack.path_id, 2)); } @@ -3501,42 +3495,6 @@ EXPECT_FALSE(connection_.connected()); } -TEST_P(QuicConnectionTest, TimeoutAfter5ServerRTOs) { - FLAGS_quic_reloadable_flag_quic_only_5rto_client_side = true; - connection_.SetMaxTailLossProbes(2); - set_perspective(Perspective::IS_SERVER); - QuicFramerPeer::SetPerspective(QuicConnectionPeer::GetFramer(&connection_), - Perspective::IS_SERVER); - creator_->StopSendingVersion(); - EXPECT_TRUE(connection_.connected()); - EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); - QuicConfig config; - QuicTagVector connection_options; - connection_options.push_back(k5RTO); - config.SetConnectionOptionsToSend(connection_options); - connection_.SetFromConfig(config); - - // Send stream data. - SendStreamDataToPeer(kClientDataStreamId1, "foo", 0, kFin, nullptr); - - EXPECT_CALL(visitor_, OnPathDegrading()); - // Fire the retransmission alarm 6 times, twice for TLP and 4 times for RTO. - for (int i = 0; i < 6; ++i) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); - connection_.GetRetransmissionAlarm()->Fire(); - EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet()); - EXPECT_TRUE(connection_.connected()); - } - - EXPECT_EQ(2u, connection_.sent_packet_manager().GetConsecutiveTlpCount()); - EXPECT_EQ(4u, connection_.sent_packet_manager().GetConsecutiveRtoCount()); - // The 5th RTO should not time out server side. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); - connection_.GetRetransmissionAlarm()->Fire(); - EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet()); - EXPECT_TRUE(connection_.connected()); -} - TEST_P(QuicConnectionTest, SendScheduler) { // Test that if we send a packet without delay, it is not queued. QuicPacket* packet = ConstructDataPacket(kDefaultPathId, 1, !kHasStopWaiting); @@ -4332,8 +4290,8 @@ frames.push_back(QuicFrame(&frame1_)); std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames)); char buffer[kMaxPacketSize]; - size_t encrypted_length = framer_.EncryptPayload( - ENCRYPTION_NONE, kDefaultPathId, 12, *packet, buffer, kMaxPacketSize); + size_t encrypted_length = framer_.EncryptPayload(ENCRYPTION_NONE, 12, *packet, + buffer, kMaxPacketSize); framer_.set_version(version()); connection_.ProcessUdpPacket( @@ -4367,8 +4325,8 @@ frames.push_back(QuicFrame(&frame1_)); std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames)); char buffer[kMaxPacketSize]; - size_t encrypted_length = framer_.EncryptPayload( - ENCRYPTION_NONE, kDefaultPathId, 12, *packet, buffer, kMaxPacketSize); + size_t encrypted_length = framer_.EncryptPayload(ENCRYPTION_NONE, 12, *packet, + buffer, kMaxPacketSize); framer_.set_version(version()); BlockOnNextWrite(); @@ -4409,8 +4367,8 @@ frames.push_back(QuicFrame(&frame1_)); std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames)); char buffer[kMaxPacketSize]; - size_t encryped_length = framer_.EncryptPayload( - ENCRYPTION_NONE, kDefaultPathId, 12, *packet, buffer, kMaxPacketSize); + size_t encryped_length = framer_.EncryptPayload(ENCRYPTION_NONE, 12, *packet, + buffer, kMaxPacketSize); framer_.set_version(version()); set_perspective(Perspective::IS_SERVER); @@ -4448,7 +4406,7 @@ std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames)); char buffer[kMaxPacketSize]; size_t encrypted_length = peer_framer_.EncryptPayload( - ENCRYPTION_NONE, kDefaultPathId, 12, *packet, buffer, kMaxPacketSize); + ENCRYPTION_NONE, 12, *packet, buffer, kMaxPacketSize); ASSERT_NE(0u, encrypted_length); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); @@ -4537,7 +4495,7 @@ EXPECT_TRUE(nullptr != packet.get()); char buffer[kMaxPacketSize]; size_t encrypted_length = peer_framer_.EncryptPayload( - ENCRYPTION_NONE, kDefaultPathId, 1, *packet, buffer, kMaxPacketSize); + ENCRYPTION_NONE, 1, *packet, buffer, kMaxPacketSize); EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, _, ConnectionCloseSource::FROM_PEER));
diff --git a/net/quic/core/quic_crypto_client_stream.h b/net/quic/core/quic_crypto_client_stream.h index 6cbdad52..7327f311 100644 --- a/net/quic/core/quic_crypto_client_stream.h +++ b/net/quic/core/quic_crypto_client_stream.h
@@ -21,7 +21,6 @@ namespace net { namespace test { -class CryptoTestUtils; class QuicChromiumClientSessionPeer; } // namespace test @@ -142,7 +141,6 @@ QuicCryptoClientStream* stream_; }; - friend class test::CryptoTestUtils; friend class test::QuicChromiumClientSessionPeer; enum State {
diff --git a/net/quic/core/quic_crypto_client_stream_test.cc b/net/quic/core/quic_crypto_client_stream_test.cc index bbc2f372..571ca249 100644 --- a/net/quic/core/quic_crypto_client_stream_test.cc +++ b/net/quic/core/quic_crypto_client_stream_test.cc
@@ -36,7 +36,7 @@ public: QuicCryptoClientStreamTest() : server_id_(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED), - crypto_config_(CryptoTestUtils::ProofVerifierForTesting()) { + crypto_config_(crypto_test_utils::ProofVerifierForTesting()) { CreateConnection(); } @@ -53,9 +53,9 @@ void CompleteCryptoHandshake() { stream()->CryptoConnect(); QuicConfig config; - CryptoTestUtils::HandshakeWithFakeServer(&config, &server_helper_, - &alarm_factory_, connection_, - stream(), server_options_); + crypto_test_utils::HandshakeWithFakeServer(&config, &server_helper_, + &alarm_factory_, connection_, + stream(), server_options_); } void ConstructHandshakeMessage() { @@ -74,7 +74,7 @@ CryptoHandshakeMessage message_; std::unique_ptr<QuicData> message_data_; QuicCryptoClientConfig crypto_config_; - CryptoTestUtils::FakeServerOptions server_options_; + crypto_test_utils::FakeServerOptions server_options_; }; TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) { @@ -244,20 +244,40 @@ // Build a server config update message with certificates QuicCryptoServerConfig crypto_config( QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), - CryptoTestUtils::ProofSourceForTesting()); - CryptoTestUtils::FakeServerOptions options; - CryptoTestUtils::SetupCryptoServerConfigForTest( + crypto_test_utils::ProofSourceForTesting()); + crypto_test_utils::FakeServerOptions options; + crypto_test_utils::SetupCryptoServerConfigForTest( connection_->clock(), QuicRandom::GetInstance(), &crypto_config, options); SourceAddressTokens tokens; QuicCompressedCertsCache cache(1); CachedNetworkParameters network_params; CryptoHandshakeMessage server_config_update; - EXPECT_TRUE(crypto_config.BuildServerConfigUpdateMessage( + + class Callback : public BuildServerConfigUpdateMessageResultCallback { + public: + Callback(bool* ok, CryptoHandshakeMessage* message) + : ok_(ok), message_(message) {} + void Run(bool ok, const CryptoHandshakeMessage& message) override { + *ok_ = ok; + *message_ = message; + } + + private: + bool* ok_; + CryptoHandshakeMessage* message_; + }; + + // Note: relies on the callback being invoked synchronously + bool ok = false; + crypto_config.BuildServerConfigUpdateMessage( session_->connection()->version(), stream()->chlo_hash(), tokens, QuicSocketAddress(QuicIpAddress::Loopback6(), 1234), QuicIpAddress::Loopback6(), connection_->clock(), QuicRandom::GetInstance(), &cache, stream()->crypto_negotiated_params(), - &network_params, QuicTagVector(), &server_config_update)); + &network_params, QuicTagVector(), + std::unique_ptr<BuildServerConfigUpdateMessageResultCallback>( + new Callback(&ok, &server_config_update))); + EXPECT_TRUE(ok); std::unique_ptr<QuicData> data( CryptoFramer::ConstructHandshakeMessage(server_config_update)); @@ -334,10 +354,10 @@ class QuicCryptoClientStreamStatelessTest : public ::testing::Test { public: QuicCryptoClientStreamStatelessTest() - : client_crypto_config_(CryptoTestUtils::ProofVerifierForTesting()), + : client_crypto_config_(crypto_test_utils::ProofVerifierForTesting()), server_crypto_config_(QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), - CryptoTestUtils::ProofSourceForTesting()), + crypto_test_utils::ProofSourceForTesting()), server_compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), server_id_(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED) { @@ -358,9 +378,9 @@ void AdvanceHandshakeWithFakeServer() { client_session_->GetCryptoStream()->CryptoConnect(); - CryptoTestUtils::AdvanceHandshake(client_connection_, - client_session_->GetCryptoStream(), 0, - server_connection_, server_stream(), 0); + crypto_test_utils::AdvanceHandshake(client_connection_, + client_session_->GetCryptoStream(), 0, + server_connection_, server_stream(), 0); } // Initializes the server_stream_ for stateless rejects. @@ -373,8 +393,8 @@ &server_connection_, &server_session); CHECK(server_session); server_session_.reset(server_session); - CryptoTestUtils::FakeServerOptions options; - CryptoTestUtils::SetupCryptoServerConfigForTest( + crypto_test_utils::FakeServerOptions options; + crypto_test_utils::SetupCryptoServerConfigForTest( server_connection_->clock(), server_connection_->random_generator(), &server_crypto_config_, options); FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support = true;
diff --git a/net/quic/core/quic_crypto_server_stream.cc b/net/quic/core/quic_crypto_server_stream.cc index e08827bd..613692a 100644 --- a/net/quic/core/quic_crypto_server_stream.cc +++ b/net/quic/core/quic_crypto_server_stream.cc
@@ -6,7 +6,6 @@ #include <memory> -#include "crypto/secure_hash.h" #include "net/quic/core/crypto/crypto_protocol.h" #include "net/quic/core/crypto/crypto_utils.h" #include "net/quic/core/crypto/quic_crypto_server_config.h" @@ -18,6 +17,7 @@ #include "net/quic/core/quic_session.h" #include "net/quic/platform/api/quic_logging.h" #include "net/quic/platform/api/quic_text_utils.h" +#include "third_party/boringssl/src/include/openssl/sha.h" using base::StringPiece; using std::string; @@ -284,55 +284,27 @@ return; } - if (FLAGS_quic_reloadable_flag_enable_async_get_proof) { - if (send_server_config_update_cb_ != nullptr) { - QUIC_DVLOG(1) - << "Skipped server config update since one is already in progress"; - return; - } - - std::unique_ptr<SendServerConfigUpdateCallback> cb( - new SendServerConfigUpdateCallback(this)); - send_server_config_update_cb_ = cb.get(); - - crypto_config_->BuildServerConfigUpdateMessage( - session()->connection()->version(), chlo_hash_, - previous_source_address_tokens_, - session()->connection()->self_address(), - session()->connection()->peer_address().host(), - session()->connection()->clock(), - session()->connection()->random_generator(), compressed_certs_cache_, - *crypto_negotiated_params_, cached_network_params, - (session()->config()->HasReceivedConnectionOptions() - ? session()->config()->ReceivedConnectionOptions() - : QuicTagVector()), - std::move(cb)); + if (send_server_config_update_cb_ != nullptr) { + QUIC_DVLOG(1) + << "Skipped server config update since one is already in progress"; return; } - CryptoHandshakeMessage server_config_update_message; - if (!crypto_config_->BuildServerConfigUpdateMessage( - session()->connection()->version(), chlo_hash_, - previous_source_address_tokens_, - session()->connection()->self_address(), - session()->connection()->peer_address().host(), - session()->connection()->clock(), - session()->connection()->random_generator(), compressed_certs_cache_, - *crypto_negotiated_params_, cached_network_params, - (session()->config()->HasReceivedConnectionOptions() - ? session()->config()->ReceivedConnectionOptions() - : QuicTagVector()), - &server_config_update_message)) { - QUIC_DVLOG(1) << "Server: Failed to build server config update (SCUP)!"; - return; - } + std::unique_ptr<SendServerConfigUpdateCallback> cb( + new SendServerConfigUpdateCallback(this)); + send_server_config_update_cb_ = cb.get(); - QUIC_DVLOG(1) << "Server: Sending server config update: " - << server_config_update_message.DebugString(); - const QuicData& data = server_config_update_message.GetSerialized(); - WriteOrBufferData(StringPiece(data.data(), data.length()), false, nullptr); - - ++num_server_config_update_messages_sent_; + crypto_config_->BuildServerConfigUpdateMessage( + session()->connection()->version(), chlo_hash_, + previous_source_address_tokens_, session()->connection()->self_address(), + session()->connection()->peer_address().host(), + session()->connection()->clock(), + session()->connection()->random_generator(), compressed_certs_cache_, + *crypto_negotiated_params_, cached_network_params, + (session()->config()->HasReceivedConnectionOptions() + ? session()->config()->ReceivedConnectionOptions() + : QuicTagVector()), + std::move(cb)); } QuicCryptoServerStream::SendServerConfigUpdateCallback:: @@ -417,11 +389,9 @@ } const string& channel_id(crypto_negotiated_params_->channel_id); - std::unique_ptr<crypto::SecureHash> hash( - crypto::SecureHash::Create(crypto::SecureHash::SHA256)); - hash->Update(channel_id.data(), channel_id.size()); - uint8_t digest[32]; - hash->Finish(digest, sizeof(digest)); + uint8_t digest[SHA256_DIGEST_LENGTH]; + SHA256(reinterpret_cast<const uint8_t*>(channel_id.data()), channel_id.size(), + digest); QuicTextUtils::Base64Encode(digest, arraysize(digest), output); return true;
diff --git a/net/quic/core/quic_crypto_server_stream.h b/net/quic/core/quic_crypto_server_stream.h index 721a276..893fbe97 100644 --- a/net/quic/core/quic_crypto_server_stream.h +++ b/net/quic/core/quic_crypto_server_stream.h
@@ -26,7 +26,6 @@ class QuicCryptoServerStreamBase; namespace test { -class CryptoTestUtils; class QuicCryptoServerStreamPeer; } // namespace test @@ -139,7 +138,6 @@ virtual void OverrideQuicConfigDefaults(QuicConfig* config); private: - friend class test::CryptoTestUtils; friend class test::QuicCryptoServerStreamPeer; class ValidateCallback : public ValidateClientHelloResultCallback {
diff --git a/net/quic/core/quic_crypto_server_stream_test.cc b/net/quic/core/quic_crypto_server_stream_test.cc index 0c693262..d7330b08 100644 --- a/net/quic/core/quic_crypto_server_stream_test.cc +++ b/net/quic/core/quic_crypto_server_stream_test.cc
@@ -59,7 +59,8 @@ class QuicCryptoServerStreamTest : public ::testing::TestWithParam<bool> { public: QuicCryptoServerStreamTest() - : QuicCryptoServerStreamTest(CryptoTestUtils::ProofSourceForTesting()) {} + : QuicCryptoServerStreamTest(crypto_test_utils::ProofSourceForTesting()) { + } explicit QuicCryptoServerStreamTest(std::unique_ptr<ProofSource> proof_source) : server_crypto_config_(QuicCryptoServerConfig::TESTING, @@ -68,7 +69,7 @@ server_compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), server_id_(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED), - client_crypto_config_(CryptoTestUtils::ProofVerifierForTesting()) { + client_crypto_config_(crypto_test_utils::ProofVerifierForTesting()) { FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support = false; } @@ -96,9 +97,9 @@ &server_connection_, &server_session); CHECK(server_session); server_session_.reset(server_session); - CryptoTestUtils::FakeServerOptions options; + crypto_test_utils::FakeServerOptions options; options.token_binding_params = QuicTagVector{kTB10}; - CryptoTestUtils::SetupCryptoServerConfigForTest( + crypto_test_utils::SetupCryptoServerConfigForTest( server_connection_->clock(), server_connection_->random_generator(), &server_crypto_config_, options); } @@ -134,7 +135,7 @@ int CompleteCryptoHandshake() { CHECK(server_connection_); CHECK(server_session_ != nullptr); - return CryptoTestUtils::HandshakeWithFakeClient( + return crypto_test_utils::HandshakeWithFakeClient( helpers_.back().get(), alarm_factories_.back().get(), server_connection_, server_stream(), server_id_, client_options_); } @@ -147,8 +148,8 @@ EXPECT_CALL(*client_session_, OnProofValid(_)).Times(testing::AnyNumber()); client_stream()->CryptoConnect(); - CryptoTestUtils::AdvanceHandshake(client_connection_, client_stream(), 0, - server_connection_, server_stream(), 0); + crypto_test_utils::AdvanceHandshake(client_connection_, client_stream(), 0, + server_connection_, server_stream(), 0); } protected: @@ -174,7 +175,7 @@ CryptoHandshakeMessage message_; std::unique_ptr<QuicData> message_data_; - CryptoTestUtils::FakeClientOptions client_options_; + crypto_test_utils::FakeClientOptions client_options_; // Which QUIC versions the client and server support. QuicVersionVector supported_versions_ = AllSupportedVersions(); @@ -339,7 +340,7 @@ client_stream()->CryptoConnect(); - CryptoTestUtils::CommunicateHandshakeMessages( + crypto_test_utils::CommunicateHandshakeMessages( client_connection_, client_stream(), server_connection_, server_stream()); EXPECT_EQ(1, client_stream()->num_sent_client_hellos()); @@ -417,7 +418,7 @@ TEST_P(QuicCryptoServerStreamTest, SendSCUPAfterHandshakeComplete) { // Do not send MAX_HEADER_LIST_SIZE SETTING frame. // TODO(fayang): This SETTING frame cannot be decrypted and - // CryptoTestUtils::MovePackets stops processing parsing following packets. + // crypto_test_utils::MovePackets stops processing parsing following packets. // Actually, crypto stream test should use QuicSession instead of // QuicSpdySession (b/32366134). FLAGS_quic_reloadable_flag_quic_send_max_header_list_size = false; @@ -437,8 +438,8 @@ // Send a SCUP message and ensure that the client was able to verify it. EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0); server_stream()->SendServerConfigUpdate(nullptr); - CryptoTestUtils::AdvanceHandshake(client_connection_, client_stream(), 1, - server_connection_, server_stream(), 1); + crypto_test_utils::AdvanceHandshake(client_connection_, client_stream(), 1, + server_connection_, server_stream(), 1); EXPECT_EQ(1, server_stream()->NumServerConfigUpdateMessagesSent()); EXPECT_EQ(1, client_stream()->num_scup_messages_received());
diff --git a/net/quic/core/quic_crypto_stream_test.cc b/net/quic/core/quic_crypto_stream_test.cc index 5ef4aa9..16c6d84 100644 --- a/net/quic/core/quic_crypto_stream_test.cc +++ b/net/quic/core/quic_crypto_stream_test.cc
@@ -87,8 +87,8 @@ const CryptoHandshakeMessage& message = (*stream_.messages())[0]; EXPECT_EQ(kSHLO, message.tag()); EXPECT_EQ(2u, message.tag_value_map().size()); - EXPECT_EQ("abc", CryptoTestUtils::GetValueForTag(message, 1)); - EXPECT_EQ("def", CryptoTestUtils::GetValueForTag(message, 2)); + EXPECT_EQ("abc", crypto_test_utils::GetValueForTag(message, 1)); + EXPECT_EQ("def", crypto_test_utils::GetValueForTag(message, 2)); } TEST_F(QuicCryptoStreamTest, ProcessBadData) {
diff --git a/net/quic/core/quic_flags_list.h b/net/quic/core/quic_flags_list.h index 358a4ea..9a738da 100644 --- a/net/quic/core/quic_flags_list.h +++ b/net/quic/core/quic_flags_list.h
@@ -65,19 +65,12 @@ // If true, re-enables QUIC_VERSION_36. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_36_v3, true) -// If true, use async codepaths to invoke ProofSource::GetProof. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_enable_async_get_proof, true) - // If true, only open limited number of quic sessions per epoll event. Leave the // rest to next event. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_limit_num_new_sessions_per_epoll_loop, true) -// Only close the connection on the 5th RTO client side when the 5RTO option -// is enabled. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_only_5rto_client_side, false) - // If true, QUIC server push will enabled by default. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_server_push_by_default, @@ -136,13 +129,6 @@ FLAGS_quic_reloadable_flag_quic_headers_stream_release_sequencer_buffer, true) -// Set the retransmission alarm only when there are unacked -// retransmittable packets. -QUIC_FLAG( - bool, - FLAGS_quic_reloadable_flag_quic_more_conservative_retransmission_alarm, - true) - // Enable QUIC force HOL blocking experiment. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_force_hol_blocking, true) @@ -173,7 +159,7 @@ // If true, QUIC cubic code will use the event time when adjusting CWND after an // ACK instead of the clock\'s current approximate time. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_use_event_time, false) +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_use_event_time, true) // If true, lazy allocate and early release memeory used in // QuicStreamSequencerBuffer to buffer incoming data.
diff --git a/net/quic/core/quic_framer.cc b/net/quic/core/quic_framer.cc index 1ae1e3e..f17caa1e 100644 --- a/net/quic/core/quic_framer.cc +++ b/net/quic/core/quic_framer.cc
@@ -1573,7 +1573,7 @@ char* buffer) { size_t output_length = 0; if (!encrypter_[level]->EncryptPacket( - quic_version_, path_id, packet_number, + quic_version_, packet_number, StringPiece(buffer, ad_len), // Associated data StringPiece(buffer + ad_len, total_len - ad_len), // Plaintext buffer + ad_len, // Destination buffer @@ -1586,7 +1586,6 @@ } size_t QuicFramer::EncryptPayload(EncryptionLevel level, - QuicPathId path_id, QuicPacketNumber packet_number, const QuicPacket& packet, char* buffer, @@ -1601,7 +1600,7 @@ // Encrypt the plaintext into the buffer. size_t output_length = 0; if (!encrypter_[level]->EncryptPacket( - quic_version_, path_id, packet_number, associated_data, + quic_version_, packet_number, associated_data, packet.Plaintext(quic_version_), buffer + ad_len, &output_length, buffer_len - ad_len)) { RaiseError(QUIC_ENCRYPTION_FAILURE); @@ -1643,8 +1642,8 @@ header.public_header.packet_number_length); bool success = decrypter_->DecryptPacket( - quic_version_, header.path_id, header.packet_number, associated_data, - encrypted, decrypted_buffer, decrypted_length, buffer_length); + quic_version_, header.packet_number, associated_data, encrypted, + decrypted_buffer, decrypted_length, buffer_length); if (success) { visitor_->OnDecryptedPacket(decrypter_level_); } else if (alternative_decrypter_.get() != nullptr) { @@ -1667,8 +1666,8 @@ if (try_alternative_decryption) { success = alternative_decrypter_->DecryptPacket( - quic_version_, header.path_id, header.packet_number, associated_data, - encrypted, decrypted_buffer, decrypted_length, buffer_length); + quic_version_, header.packet_number, associated_data, encrypted, + decrypted_buffer, decrypted_length, buffer_length); } if (success) { visitor_->OnDecryptedPacket(alternative_decrypter_level_);
diff --git a/net/quic/core/quic_framer.h b/net/quic/core/quic_framer.h index a40b211..524df7f 100644 --- a/net/quic/core/quic_framer.h +++ b/net/quic/core/quic_framer.h
@@ -309,7 +309,6 @@ // Returns the length of the data encrypted into |buffer| if |buffer_len| is // long enough, and otherwise 0. size_t EncryptPayload(EncryptionLevel level, - QuicPathId path_id, QuicPacketNumber packet_number, const QuicPacket& packet, char* buffer,
diff --git a/net/quic/core/quic_framer_test.cc b/net/quic/core/quic_framer_test.cc index 645c2c6..a4611ed 100644 --- a/net/quic/core/quic_framer_test.cc +++ b/net/quic/core/quic_framer_test.cc
@@ -113,7 +113,6 @@ bool SetKey(StringPiece key) override { return true; } bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; } bool EncryptPacket(QuicVersion version, - QuicPathId path_id, QuicPacketNumber packet_number, StringPiece associated_data, StringPiece plaintext, @@ -121,7 +120,6 @@ size_t* output_length, size_t max_output_length) override { version_ = version; - path_id_ = path_id; packet_number_ = packet_number; associated_data_ = associated_data.as_string(); plaintext_ = plaintext.as_string(); @@ -142,7 +140,6 @@ QuicVersion version_; Perspective perspective_; - QuicPathId path_id_; QuicPacketNumber packet_number_; string associated_data_; string plaintext_; @@ -161,7 +158,6 @@ return true; } bool DecryptPacket(QuicVersion version, - QuicPathId path_id, QuicPacketNumber packet_number, StringPiece associated_data, StringPiece ciphertext, @@ -169,7 +165,6 @@ size_t* output_length, size_t max_output_length) override { version_ = version; - path_id_ = path_id; packet_number_ = packet_number; associated_data_ = associated_data.as_string(); ciphertext_ = ciphertext.as_string(); @@ -184,7 +179,6 @@ uint32_t cipher_id() const override { return 0xFFFFFFF2; } QuicVersion version_; Perspective perspective_; - QuicPathId path_id_; QuicPacketNumber packet_number_; string associated_data_; string ciphertext_; @@ -3772,9 +3766,8 @@ !kIncludeVersion, !kIncludePathId, !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER)); char buffer[kMaxPacketSize]; - size_t encrypted_length = - framer_.EncryptPayload(ENCRYPTION_NONE, kDefaultPathId, packet_number, - *raw, buffer, kMaxPacketSize); + size_t encrypted_length = framer_.EncryptPayload( + ENCRYPTION_NONE, packet_number, *raw, buffer, kMaxPacketSize); ASSERT_NE(0u, encrypted_length); EXPECT_TRUE(CheckEncryption(kDefaultPathId, packet_number, raw.get())); @@ -3808,9 +3801,8 @@ kIncludeVersion, !kIncludePathId, !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER)); char buffer[kMaxPacketSize]; - size_t encrypted_length = - framer_.EncryptPayload(ENCRYPTION_NONE, kDefaultPathId, packet_number, - *raw, buffer, kMaxPacketSize); + size_t encrypted_length = framer_.EncryptPayload( + ENCRYPTION_NONE, packet_number, *raw, buffer, kMaxPacketSize); ASSERT_NE(0u, encrypted_length); EXPECT_TRUE(CheckEncryption(kDefaultPathId, packet_number, raw.get())); @@ -3845,7 +3837,7 @@ PACKET_6BYTE_PACKET_NUMBER)); char buffer[kMaxPacketSize]; size_t encrypted_length = framer_.EncryptPayload( - ENCRYPTION_NONE, kPathId, packet_number, *raw, buffer, kMaxPacketSize); + ENCRYPTION_NONE, packet_number, *raw, buffer, kMaxPacketSize); ASSERT_NE(0u, encrypted_length); EXPECT_TRUE(CheckEncryption(kPathId, packet_number, raw.get())); @@ -3882,7 +3874,7 @@ PACKET_6BYTE_PACKET_NUMBER)); char buffer[kMaxPacketSize]; size_t encrypted_length = framer_.EncryptPayload( - ENCRYPTION_NONE, kPathId, packet_number, *raw, buffer, kMaxPacketSize); + ENCRYPTION_NONE, packet_number, *raw, buffer, kMaxPacketSize); ASSERT_NE(0u, encrypted_length); EXPECT_TRUE(CheckEncryption(kPathId, packet_number, raw.get())); @@ -3904,9 +3896,9 @@ std::unique_ptr<QuicPacket> raw_ack_packet(BuildDataPacket(header, frames)); ASSERT_TRUE(raw_ack_packet != nullptr); char buffer[kMaxPacketSize]; - size_t encrypted_length = framer_.EncryptPayload( - ENCRYPTION_NONE, kDefaultPathId, header.packet_number, *raw_ack_packet, - buffer, kMaxPacketSize); + size_t encrypted_length = + framer_.EncryptPayload(ENCRYPTION_NONE, header.packet_number, + *raw_ack_packet, buffer, kMaxPacketSize); ASSERT_NE(0u, encrypted_length); // Now make sure we can turn our ack packet back into an ack frame. ASSERT_TRUE(framer_.ProcessPacket( @@ -3936,9 +3928,9 @@ BuildDataPacket(header, frames, 500)); ASSERT_TRUE(raw_ack_packet != nullptr); char buffer[kMaxPacketSize]; - size_t encrypted_length = framer_.EncryptPayload( - ENCRYPTION_NONE, kDefaultPathId, header.packet_number, *raw_ack_packet, - buffer, kMaxPacketSize); + size_t encrypted_length = + framer_.EncryptPayload(ENCRYPTION_NONE, header.packet_number, + *raw_ack_packet, buffer, kMaxPacketSize); ASSERT_NE(0u, encrypted_length); // Now make sure we can turn our ack packet back into an ack frame. ASSERT_TRUE(framer_.ProcessPacket( @@ -3969,9 +3961,9 @@ ASSERT_TRUE(raw_ack_packet != nullptr); char buffer[kMaxPacketSize]; - size_t encrypted_length = framer_.EncryptPayload( - ENCRYPTION_NONE, kDefaultPathId, header.packet_number, *raw_ack_packet, - buffer, kMaxPacketSize); + size_t encrypted_length = + framer_.EncryptPayload(ENCRYPTION_NONE, header.packet_number, + *raw_ack_packet, buffer, kMaxPacketSize); ASSERT_NE(0u, encrypted_length); // Now make sure we can turn our ack packet back into an ack frame.
diff --git a/net/quic/core/quic_sent_packet_manager.cc b/net/quic/core/quic_sent_packet_manager.cc index 852fa09..3b601e25 100644 --- a/net/quic/core/quic_sent_packet_manager.cc +++ b/net/quic/core/quic_sent_packet_manager.cc
@@ -781,8 +781,7 @@ pending_timer_transmission_count_ > 0) { return QuicTime::Zero(); } - if (FLAGS_quic_reloadable_flag_quic_more_conservative_retransmission_alarm && - !unacked_packets_.HasUnackedRetransmittableFrames()) { + if (!unacked_packets_.HasUnackedRetransmittableFrames()) { return QuicTime::Zero(); } switch (GetRetransmissionMode()) {
diff --git a/net/quic/core/quic_server_session_base_test.cc b/net/quic/core/quic_server_session_base_test.cc index 09c9c28..6e18cd5 100644 --- a/net/quic/core/quic_server_session_base_test.cc +++ b/net/quic/core/quic_server_session_base_test.cc
@@ -120,7 +120,7 @@ class QuicServerSessionBaseTest : public ::testing::TestWithParam<QuicVersion> { protected: QuicServerSessionBaseTest() - : QuicServerSessionBaseTest(CryptoTestUtils::ProofSourceForTesting()) {} + : QuicServerSessionBaseTest(crypto_test_utils::ProofSourceForTesting()) {} explicit QuicServerSessionBaseTest(std::unique_ptr<ProofSource> proof_source) : crypto_config_(QuicCryptoServerConfig::TESTING, @@ -602,14 +602,13 @@ // ProofSource::GetProof. Delay the completion of the operation until after the // stream has been destroyed, and verify that there are no memory bugs. TEST_P(StreamMemberLifetimeTest, Basic) { - FLAGS_quic_reloadable_flag_enable_async_get_proof = true; FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support = true; FLAGS_quic_reloadable_flag_quic_use_cheap_stateless_rejects = true; FLAGS_quic_reloadable_flag_quic_create_session_after_insertion = true; const QuicClock* clock = helper_.GetClock(); QuicVersion version = AllSupportedVersions().front(); - CryptoHandshakeMessage chlo = CryptoTestUtils::GenerateDefaultInchoateCHLO( + CryptoHandshakeMessage chlo = crypto_test_utils::GenerateDefaultInchoateCHLO( clock, version, &crypto_config_); chlo.SetVector(kCOPT, QuicTagVector{kSREJ}); std::vector<QuicVersion> packet_version_list = {version};
diff --git a/net/quic/core/quic_session_test.cc b/net/quic/core/quic_session_test.cc index 84c8db3e..edc9356 100644 --- a/net/quic/core/quic_session_test.cc +++ b/net/quic/core/quic_session_test.cc
@@ -1220,7 +1220,7 @@ TEST_P(QuicSessionTestServer, EnableFHOLThroughConfigOption) { QuicConfigPeer::SetReceivedForceHolBlocking(session_.config()); session_.OnConfigNegotiated(); - if (version() <= QUIC_VERSION_35) { + if (version() != QUIC_VERSION_36) { EXPECT_FALSE(session_.force_hol_blocking()); } else { EXPECT_TRUE(session_.force_hol_blocking()); @@ -1305,7 +1305,7 @@ TEST_P(QuicSessionTestClient, EnableFHOLThroughConfigOption) { session_.config()->SetForceHolBlocking(); session_.OnConfigNegotiated(); - if (version() <= QUIC_VERSION_35) { + if (version() != QUIC_VERSION_36) { EXPECT_FALSE(session_.force_hol_blocking()); } else { EXPECT_TRUE(session_.force_hol_blocking());
diff --git a/net/quic/core/quic_spdy_session.cc b/net/quic/core/quic_spdy_session.cc index fe5bae6..29f71db0 100644 --- a/net/quic/core/quic_spdy_session.cc +++ b/net/quic/core/quic_spdy_session.cc
@@ -571,7 +571,7 @@ } const QuicVersion version = connection()->version(); if (FLAGS_quic_reloadable_flag_quic_enable_force_hol_blocking && - version > QUIC_VERSION_35 && config()->ForceHolBlocking(perspective())) { + version == QUIC_VERSION_36 && config()->ForceHolBlocking(perspective())) { force_hol_blocking_ = true; // Since all streams are tunneled through the headers stream, it // is important that headers stream never flow control blocks.
diff --git a/net/quic/quartc/quartc_session.cc b/net/quic/quartc/quartc_session.cc index e31f72b..3664d89 100644 --- a/net/quic/quartc/quartc_session.cc +++ b/net/quic/quartc/quartc_session.cc
@@ -28,30 +28,22 @@ ~DummyProofSource() override {} // ProofSource override. - bool GetProof( - const net::QuicSocketAddress& server_addr, - const std::string& hostname, - const std::string& server_config, - net::QuicVersion quic_version, - base::StringPiece chlo_hash, - const net::QuicTagVector& connection_options, - net::QuicReferenceCountedPointer<net::ProofSource::Chain>* out_chain, - net::QuicCryptoProof* proof) override { - std::vector<std::string> certs; - certs.push_back("Dummy cert"); - *out_chain = new ProofSource::Chain(certs); - proof->signature = "Dummy signature"; - proof->leaf_cert_scts = "Dummy timestamp"; - return true; - } - void GetProof(const net::QuicSocketAddress& server_addr, const std::string& hostname, const std::string& server_config, net::QuicVersion quic_version, base::StringPiece chlo_hash, const net::QuicTagVector& connection_options, - std::unique_ptr<Callback> callback) override {} + std::unique_ptr<Callback> callback) override { + net::QuicReferenceCountedPointer<net::ProofSource::Chain> chain; + net::QuicCryptoProof proof; + std::vector<std::string> certs; + certs.push_back("Dummy cert"); + chain = new ProofSource::Chain(certs); + proof.signature = "Dummy signature"; + proof.leaf_cert_scts = "Dummy timestamp"; + callback->Run(true, chain, proof, nullptr /* details */); + } }; // Used by QuicCryptoClientConfig to ignore the peer's credentials
diff --git a/net/quic/quartc/quartc_session_test.cc b/net/quic/quartc/quartc_session_test.cc index fc190057..6bc2b59 100644 --- a/net/quic/quartc/quartc_session_test.cc +++ b/net/quic/quartc/quartc_session_test.cc
@@ -53,24 +53,6 @@ explicit FakeProofSource(bool success) : success_(success) {} // ProofSource override. - bool GetProof(const QuicSocketAddress& server_ip, - const std::string& hostname, - const std::string& server_config, - net::QuicVersion quic_version, - base::StringPiece chlo_hash, - const net::QuicTagVector& connection_options, - QuicReferenceCountedPointer<net::ProofSource::Chain>* out_certs, - net::QuicCryptoProof* proof) override { - if (success_) { - std::vector<std::string> certs; - certs.push_back("Required to establish handshake"); - *out_certs = new ProofSource::Chain(certs); - proof->signature = "Signature"; - proof->leaf_cert_scts = "Time"; - } - return success_; - } - void GetProof(const QuicSocketAddress& server_ip, const std::string& hostname, const std::string& server_config, @@ -78,7 +60,16 @@ base::StringPiece chlo_hash, const net::QuicTagVector& connection_options, std::unique_ptr<Callback> callback) override { - LOG(INFO) << "GetProof() providing dummy credentials for insecure QUIC"; + QuicReferenceCountedPointer<net::ProofSource::Chain> chain; + net::QuicCryptoProof proof; + if (success_) { + std::vector<std::string> certs; + certs.push_back("Required to establish handshake"); + chain = new ProofSource::Chain(certs); + proof.signature = "Signature"; + proof.leaf_cert_scts = "Time"; + } + callback->Run(success_, chain, proof, nullptr /* details */); } private: @@ -463,20 +454,20 @@ std::unique_ptr<QuartcSessionForTest> server_peer_; }; -TEST_F(QuartcSessionTest, DISABLED_StreamConnection) { +TEST_F(QuartcSessionTest, StreamConnection) { CreateClientAndServerSessions(); StartHandshake(); TestStreamConnection(); } -TEST_F(QuartcSessionTest, DISABLED_ClientRejection) { +TEST_F(QuartcSessionTest, ClientRejection) { CreateClientAndServerSessions(false /*client_handshake_success*/, true /*server_handshake_success*/); StartHandshake(); TestDisconnectAfterFailedHandshake(); } -TEST_F(QuartcSessionTest, DISABLED_ServerRejection) { +TEST_F(QuartcSessionTest, ServerRejection) { CreateClientAndServerSessions(true /*client_handshake_success*/, false /*server_handshake_success*/); StartHandshake(); @@ -490,7 +481,7 @@ EXPECT_EQ(nullptr, client_peer_->CreateOutgoingStream(kDefaultStreamParam)); } -TEST_F(QuartcSessionTest, DISABLED_CloseQuartcStream) { +TEST_F(QuartcSessionTest, CloseQuartcStream) { CreateClientAndServerSessions(); StartHandshake(); ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed() &&
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc index f210e26..1280dd3a 100644 --- a/net/quic/test_tools/crypto_test_utils.cc +++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -27,6 +27,7 @@ #include "net/quic/platform/api/quic_text_utils.h" #include "net/quic/test_tools/quic_connection_peer.h" #include "net/quic/test_tools/quic_framer_peer.h" +#include "net/quic/test_tools/quic_stream_peer.h" #include "net/quic/test_tools/quic_test_utils.h" #include "net/quic/test_tools/simple_quic_framer.h" #include "third_party/boringssl/src/include/openssl/bn.h" @@ -41,6 +42,7 @@ namespace net { namespace test { +namespace crypto_test_utils { namespace { @@ -86,8 +88,7 @@ // A ChannelIDSource that works in asynchronous mode unless the |callback| // argument to GetChannelIDKey is nullptr. -class AsyncTestChannelIDSource : public ChannelIDSource, - public CryptoTestUtils::CallbackSource { +class AsyncTestChannelIDSource : public ChannelIDSource, public CallbackSource { public: // Takes ownership of |sync_source|, a synchronous ChannelIDSource. explicit AsyncTestChannelIDSource(ChannelIDSource* sync_source) @@ -260,14 +261,14 @@ } // anonymous namespace -CryptoTestUtils::FakeServerOptions::FakeServerOptions() {} +FakeServerOptions::FakeServerOptions() {} -CryptoTestUtils::FakeServerOptions::~FakeServerOptions() {} +FakeServerOptions::~FakeServerOptions() {} -CryptoTestUtils::FakeClientOptions::FakeClientOptions() +FakeClientOptions::FakeClientOptions() : channel_id_enabled(false), channel_id_source_async(false) {} -CryptoTestUtils::FakeClientOptions::~FakeClientOptions() {} +FakeClientOptions::~FakeClientOptions() {} namespace { // This class is used by GenerateFullCHLO() to extract SCID and STK from @@ -368,7 +369,7 @@ *out_ = result_->client_hello; out_->SetStringPiece(kSCID, scid); out_->SetStringPiece(kSourceAddressTokenTag, srct); - uint64_t xlct = CryptoTestUtils::LeafCertHashForTesting(); + uint64_t xlct = LeafCertHashForTesting(); out_->SetValue(kXLCT, xlct); } @@ -388,14 +389,12 @@ } // namespace -// static -int CryptoTestUtils::HandshakeWithFakeServer( - QuicConfig* server_quic_config, - MockQuicConnectionHelper* helper, - MockAlarmFactory* alarm_factory, - PacketSavingConnection* client_conn, - QuicCryptoClientStream* client, - const FakeServerOptions& options) { +int HandshakeWithFakeServer(QuicConfig* server_quic_config, + MockQuicConnectionHelper* helper, + MockAlarmFactory* alarm_factory, + PacketSavingConnection* client_conn, + QuicCryptoClientStream* client, + const FakeServerOptions& options) { PacketSavingConnection* server_conn = new PacketSavingConnection(helper, alarm_factory, Perspective::IS_SERVER, client_conn->supported_versions()); @@ -423,14 +422,12 @@ return client->num_sent_client_hellos(); } -// static -int CryptoTestUtils::HandshakeWithFakeClient( - MockQuicConnectionHelper* helper, - MockAlarmFactory* alarm_factory, - PacketSavingConnection* server_conn, - QuicCryptoServerStream* server, - const QuicServerId& server_id, - const FakeClientOptions& options) { +int HandshakeWithFakeClient(MockQuicConnectionHelper* helper, + MockAlarmFactory* alarm_factory, + PacketSavingConnection* server_conn, + QuicCryptoServerStream* server, + const QuicServerId& server_id, + const FakeClientOptions& options) { PacketSavingConnection* client_conn = new PacketSavingConnection(helper, alarm_factory, Perspective::IS_CLIENT); // Advance the time, because timers do not like uninitialized times. @@ -481,12 +478,10 @@ return client_session.GetCryptoStream()->num_sent_client_hellos(); } -// static -void CryptoTestUtils::SetupCryptoServerConfigForTest( - const QuicClock* clock, - QuicRandom* rand, - QuicCryptoServerConfig* crypto_config, - const FakeServerOptions& fake_options) { +void SetupCryptoServerConfigForTest(const QuicClock* clock, + QuicRandom* rand, + QuicCryptoServerConfig* crypto_config, + const FakeServerOptions& fake_options) { QuicCryptoServerConfig::ConfigOptions options; options.channel_id_enabled = true; options.token_binding_params = fake_options.token_binding_params; @@ -494,18 +489,15 @@ crypto_config->AddDefaultConfig(rand, clock, options)); } -// static -void CryptoTestUtils::CommunicateHandshakeMessages( - PacketSavingConnection* client_conn, - QuicCryptoStream* client, - PacketSavingConnection* server_conn, - QuicCryptoStream* server) { +void CommunicateHandshakeMessages(PacketSavingConnection* client_conn, + QuicCryptoStream* client, + PacketSavingConnection* server_conn, + QuicCryptoStream* server) { CommunicateHandshakeMessagesAndRunCallbacks(client_conn, client, server_conn, server, nullptr); } -// static -void CryptoTestUtils::CommunicateHandshakeMessagesAndRunCallbacks( +void CommunicateHandshakeMessagesAndRunCallbacks( PacketSavingConnection* client_conn, QuicCryptoStream* client, PacketSavingConnection* server_conn, @@ -535,14 +527,12 @@ } } -// static -std::pair<size_t, size_t> CryptoTestUtils::AdvanceHandshake( - PacketSavingConnection* client_conn, - QuicCryptoStream* client, - size_t client_i, - PacketSavingConnection* server_conn, - QuicCryptoStream* server, - size_t server_i) { +std::pair<size_t, size_t> AdvanceHandshake(PacketSavingConnection* client_conn, + QuicCryptoStream* client, + size_t client_i, + PacketSavingConnection* server_conn, + QuicCryptoStream* server, + size_t server_i) { QUIC_LOG(INFO) << "Processing " << client_conn->encrypted_packets_.size() - client_i << " packets client->server"; @@ -561,9 +551,7 @@ return std::make_pair(client_i, server_i); } -// static -string CryptoTestUtils::GetValueForTag(const CryptoHandshakeMessage& message, - QuicTag tag) { +string GetValueForTag(const CryptoHandshakeMessage& message, QuicTag tag) { QuicTagValueMap::const_iterator it = message.tag_value_map().find(tag); if (it == message.tag_value_map().end()) { return string(); @@ -571,16 +559,37 @@ return it->second; } -uint64_t CryptoTestUtils::LeafCertHashForTesting() { +uint64_t LeafCertHashForTesting() { QuicReferenceCountedPointer<ProofSource::Chain> chain; QuicSocketAddress server_address; QuicCryptoProof proof; - std::unique_ptr<ProofSource> proof_source( - CryptoTestUtils::ProofSourceForTesting()); - if (!proof_source->GetProof(server_address, "", "", - AllSupportedVersions().front(), "", - QuicTagVector(), &chain, &proof) || - chain->certs.empty()) { + std::unique_ptr<ProofSource> proof_source(ProofSourceForTesting()); + + class Callback : public ProofSource::Callback { + public: + Callback(bool* ok, QuicReferenceCountedPointer<ProofSource::Chain>* chain) + : ok_(ok), chain_(chain) {} + + void Run(bool ok, + const QuicReferenceCountedPointer<ProofSource::Chain>& chain, + const QuicCryptoProof& /* proof */, + std::unique_ptr<ProofSource::Details> /* details */) override { + *ok_ = ok; + *chain_ = chain; + } + + private: + bool* ok_; + QuicReferenceCountedPointer<ProofSource::Chain>* chain_; + }; + + // Note: relies on the callback being invoked synchronously + bool ok = false; + proof_source->GetProof( + server_address, "", "", AllSupportedVersions().front(), "", + QuicTagVector(), + std::unique_ptr<ProofSource::Callback>(new Callback(&ok, &chain))); + if (!ok || chain->certs.empty()) { DCHECK(false) << "Proof generation failed"; return 0; } @@ -641,15 +650,13 @@ const uint32_t index_; }; -CommonCertSets* CryptoTestUtils::MockCommonCertSets(StringPiece cert, - uint64_t hash, - uint32_t index) { +CommonCertSets* MockCommonCertSets(StringPiece cert, + uint64_t hash, + uint32_t index) { return new class MockCommonCertSets(cert, hash, index); } -// static -void CryptoTestUtils::FillInDummyReject(CryptoHandshakeMessage* rej, - bool reject_is_stateless) { +void FillInDummyReject(CryptoHandshakeMessage* rej, bool reject_is_stateless) { if (reject_is_stateless) { rej->set_tag(kSREJ); } else { @@ -683,29 +690,28 @@ rej->SetVector(kRREJ, reject_reasons); } -void CryptoTestUtils::CompareClientAndServerKeys( - QuicCryptoClientStream* client, - QuicCryptoServerStream* server) { - QuicFramer* client_framer = - QuicConnectionPeer::GetFramer(client->session()->connection()); - QuicFramer* server_framer = - QuicConnectionPeer::GetFramer(server->session()->connection()); +void CompareClientAndServerKeys(QuicCryptoClientStream* client, + QuicCryptoServerStream* server) { + QuicFramer* client_framer = QuicConnectionPeer::GetFramer( + QuicStreamPeer::session(client)->connection()); + QuicFramer* server_framer = QuicConnectionPeer::GetFramer( + QuicStreamPeer::session(server)->connection()); const QuicEncrypter* client_encrypter( QuicFramerPeer::GetEncrypter(client_framer, ENCRYPTION_INITIAL)); const QuicDecrypter* client_decrypter( - client->session()->connection()->decrypter()); + QuicStreamPeer::session(client)->connection()->decrypter()); const QuicEncrypter* client_forward_secure_encrypter( QuicFramerPeer::GetEncrypter(client_framer, ENCRYPTION_FORWARD_SECURE)); const QuicDecrypter* client_forward_secure_decrypter( - client->session()->connection()->alternative_decrypter()); + QuicStreamPeer::session(client)->connection()->alternative_decrypter()); const QuicEncrypter* server_encrypter( QuicFramerPeer::GetEncrypter(server_framer, ENCRYPTION_INITIAL)); const QuicDecrypter* server_decrypter( - server->session()->connection()->decrypter()); + QuicStreamPeer::session(server)->connection()->decrypter()); const QuicEncrypter* server_forward_secure_encrypter( QuicFramerPeer::GetEncrypter(server_framer, ENCRYPTION_FORWARD_SECURE)); const QuicDecrypter* server_forward_secure_decrypter( - server->session()->connection()->alternative_decrypter()); + QuicStreamPeer::session(server)->connection()->alternative_decrypter()); StringPiece client_encrypter_key = client_encrypter->GetKey(); StringPiece client_encrypter_iv = client_encrypter->GetNoncePrefix(); @@ -803,8 +809,7 @@ server_tb_ekm.data(), server_tb_ekm.length()); } -// static -QuicTag CryptoTestUtils::ParseTag(const char* tagstr) { +QuicTag ParseTag(const char* tagstr) { const size_t len = strlen(tagstr); CHECK_NE(0u, len); @@ -836,58 +841,35 @@ return tag; } -// static -CryptoHandshakeMessage CryptoTestUtils::Message(const char* message_tag, ...) { - va_list ap; - va_start(ap, message_tag); +CryptoHandshakeMessage CreateCHLO( + std::vector<std::pair<string, string>> tags_and_values) { + return CreateCHLO(tags_and_values, -1); +} +CryptoHandshakeMessage CreateCHLO( + std::vector<std::pair<string, string>> tags_and_values, + int minimum_size_bytes) { CryptoHandshakeMessage msg; - msg.set_tag(ParseTag(message_tag)); + msg.set_tag(MakeQuicTag('C', 'H', 'L', 'O')); - for (;;) { - const char* tagstr = va_arg(ap, const char*); - if (tagstr == nullptr) { - break; - } + if (minimum_size_bytes > 0) { + msg.set_minimum_size(minimum_size_bytes); + } - if (tagstr[0] == '$') { - // Special value. - const char* const special = tagstr + 1; - if (strcmp(special, "padding") == 0) { - const int min_bytes = va_arg(ap, int); - msg.set_minimum_size(min_bytes); - } else { - CHECK(false) << "Unknown special value: " << special; - } + for (const auto& tag_and_value : tags_and_values) { + const string& tag = tag_and_value.first; + const string& value = tag_and_value.second; + const QuicTag quic_tag = ParseTag(tag.c_str()); + + size_t value_len = value.length(); + if (value_len > 0 && value[0] == '#') { + // This is ascii encoded hex. + string hex_value = QuicTextUtils::HexDecode(StringPiece(&value[1])); + msg.SetStringPiece(quic_tag, hex_value); continue; } - - const QuicTag tag = ParseTag(tagstr); - const char* valuestr = va_arg(ap, const char*); - - size_t len = strlen(valuestr); - if (len > 0 && valuestr[0] == '#') { - valuestr++; - len--; - - CHECK_EQ(0u, len % 2); - std::unique_ptr<uint8_t[]> buf(new uint8_t[len / 2]); - - for (size_t i = 0; i < len / 2; i++) { - uint8_t v = 0; - CHECK(HexChar(valuestr[i * 2], &v)); - buf[i] = v << 4; - CHECK(HexChar(valuestr[i * 2 + 1], &v)); - buf[i] |= v; - } - - msg.SetStringPiece( - tag, StringPiece(reinterpret_cast<char*>(buf.get()), len / 2)); - continue; - } - - msg.SetStringPiece(tag, valuestr); + msg.SetStringPiece(quic_tag, value); } // The CryptoHandshakeMessage needs to be serialized and parsed to ensure @@ -897,21 +879,18 @@ CryptoFramer::ParseMessage(bytes->AsStringPiece())); CHECK(parsed.get()); - va_end(ap); return *parsed; } -// static -ChannelIDSource* CryptoTestUtils::ChannelIDSourceForTesting() { +ChannelIDSource* ChannelIDSourceForTesting() { return new TestChannelIDSource(); } -// static -void CryptoTestUtils::MovePackets(PacketSavingConnection* source_conn, - size_t* inout_packet_index, - QuicCryptoStream* dest_stream, - PacketSavingConnection* dest_conn, - Perspective dest_perspective) { +void MovePackets(PacketSavingConnection* source_conn, + size_t* inout_packet_index, + QuicCryptoStream* dest_stream, + PacketSavingConnection* dest_conn, + Perspective dest_perspective) { SimpleQuicFramer framer(source_conn->supported_versions(), dest_perspective); CryptoFramer crypto_framer; CryptoFramerVisitor crypto_visitor; @@ -953,29 +932,24 @@ QuicConnectionPeer::SetCurrentPacket(dest_conn, StringPiece(nullptr, 0)); } -CryptoHandshakeMessage CryptoTestUtils::GenerateDefaultInchoateCHLO( +CryptoHandshakeMessage GenerateDefaultInchoateCHLO( const QuicClock* clock, QuicVersion version, QuicCryptoServerConfig* crypto_config) { // clang-format off - return CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "AEAD", "AESG", - "KEXS", "C255", - "PUBS", CryptoTestUtils::GenerateClientPublicValuesHex().c_str(), - "NONC", CryptoTestUtils::GenerateClientNonceHex(clock, - crypto_config).c_str(), - "VER\0", QuicTagToString( - QuicVersionToQuicTag(version)).c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); + return CreateCHLO( + {{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"PUBS", GenerateClientPublicValuesHex().c_str()}, + {"NONC", GenerateClientNonceHex(clock, crypto_config).c_str()}, + {"VER\0", QuicTagToString(QuicVersionToQuicTag(version)).c_str()}}, + kClientHelloMinimumSize); // clang-format on } -string CryptoTestUtils::GenerateClientNonceHex( - const QuicClock* clock, - QuicCryptoServerConfig* crypto_config) { +string GenerateClientNonceHex(const QuicClock* clock, + QuicCryptoServerConfig* crypto_config) { net::QuicCryptoServerConfig::ConfigOptions old_config_options; net::QuicCryptoServerConfig::ConfigOptions new_config_options; old_config_options.id = "old-config-id"; @@ -998,23 +972,21 @@ return ("#" + QuicTextUtils::HexEncode(nonce)); } -string CryptoTestUtils::GenerateClientPublicValuesHex() { +string GenerateClientPublicValuesHex() { char public_value[32]; memset(public_value, 42, sizeof(public_value)); return ("#" + QuicTextUtils::HexEncode(public_value, sizeof(public_value))); } -// static -void CryptoTestUtils::GenerateFullCHLO( - const CryptoHandshakeMessage& inchoate_chlo, - QuicCryptoServerConfig* crypto_config, - QuicSocketAddress server_addr, - QuicSocketAddress client_addr, - QuicVersion version, - const QuicClock* clock, - QuicReferenceCountedPointer<QuicSignedServerConfig> proof, - QuicCompressedCertsCache* compressed_certs_cache, - CryptoHandshakeMessage* out) { +void GenerateFullCHLO(const CryptoHandshakeMessage& inchoate_chlo, + QuicCryptoServerConfig* crypto_config, + QuicSocketAddress server_addr, + QuicSocketAddress client_addr, + QuicVersion version, + const QuicClock* clock, + QuicReferenceCountedPointer<QuicSignedServerConfig> proof, + QuicCompressedCertsCache* compressed_certs_cache, + CryptoHandshakeMessage* out) { // Pass a inchoate CHLO. FullChloGenerator generator(crypto_config, server_addr, client_addr, clock, proof, compressed_certs_cache, out); @@ -1023,5 +995,6 @@ generator.GetValidateClientHelloCallback()); } +} // namespace crypto_test_utils } // namespace test } // namespace net
diff --git a/net/quic/test_tools/crypto_test_utils.h b/net/quic/test_tools/crypto_test_utils.h index 8c3565d..f8611cd5 100644 --- a/net/quic/test_tools/crypto_test_utils.h +++ b/net/quic/test_tools/crypto_test_utils.h
@@ -38,207 +38,196 @@ class PacketSavingConnection; -class CryptoTestUtils { +namespace crypto_test_utils { + +// An interface for a source of callbacks. This is used for invoking +// callbacks asynchronously. +// +// Call the RunPendingCallbacks method regularly to run the callbacks from +// this source. +class CallbackSource { public: - // An interface for a source of callbacks. This is used for invoking - // callbacks asynchronously. - // - // Call the RunPendingCallbacks method regularly to run the callbacks from - // this source. - class CallbackSource { - public: - virtual ~CallbackSource() {} + virtual ~CallbackSource() {} - // Runs pending callbacks from this source. If there is no pending - // callback, does nothing. - virtual void RunPendingCallbacks() = 0; - }; - - // FakeServerOptions bundles together a number of options for configuring the - // server in HandshakeWithFakeServer. - struct FakeServerOptions { - FakeServerOptions(); - ~FakeServerOptions(); - - // The Token Binding params that the server supports and will negotiate. - QuicTagVector token_binding_params; - }; - - // FakeClientOptions bundles together a number of options for configuring - // HandshakeWithFakeClient. - struct FakeClientOptions { - FakeClientOptions(); - ~FakeClientOptions(); - - // If channel_id_enabled is true then the client will attempt to send a - // ChannelID. - bool channel_id_enabled; - - // If channel_id_source_async is true then the client will use an async - // ChannelIDSource for testing. Ignored if channel_id_enabled is false. - bool channel_id_source_async; - - // The Token Binding params that the client supports and will negotiate. - QuicTagVector token_binding_params; - }; - - // returns: the number of client hellos that the client sent. - static int HandshakeWithFakeServer(QuicConfig* server_quic_config, - MockQuicConnectionHelper* helper, - MockAlarmFactory* alarm_factory, - PacketSavingConnection* client_conn, - QuicCryptoClientStream* client, - const FakeServerOptions& options); - - // returns: the number of client hellos that the client sent. - static int HandshakeWithFakeClient(MockQuicConnectionHelper* helper, - MockAlarmFactory* alarm_factory, - PacketSavingConnection* server_conn, - QuicCryptoServerStream* server, - const QuicServerId& server_id, - const FakeClientOptions& options); - - // SetupCryptoServerConfigForTest configures |crypto_config| - // with sensible defaults for testing. - static void SetupCryptoServerConfigForTest( - const QuicClock* clock, - QuicRandom* rand, - QuicCryptoServerConfig* crypto_config, - const FakeServerOptions& options); - - // CommunicateHandshakeMessages moves messages from |client| to |server| and - // back until |clients|'s handshake has completed. - static void CommunicateHandshakeMessages(PacketSavingConnection* client_conn, - QuicCryptoStream* client, - PacketSavingConnection* server_conn, - QuicCryptoStream* server); - - // CommunicateHandshakeMessagesAndRunCallbacks moves messages from |client| - // to |server| and back until |client|'s handshake has completed. If - // |callback_source| is not nullptr, - // CommunicateHandshakeMessagesAndRunCallbacks also runs callbacks from - // |callback_source| between processing messages. - static void CommunicateHandshakeMessagesAndRunCallbacks( - PacketSavingConnection* client_conn, - QuicCryptoStream* client, - PacketSavingConnection* server_conn, - QuicCryptoStream* server, - CallbackSource* callback_source); - - // AdvanceHandshake attempts to moves messages from |client| to |server| and - // |server| to |client|. Returns the number of messages moved. - static std::pair<size_t, size_t> AdvanceHandshake( - PacketSavingConnection* client_conn, - QuicCryptoStream* client, - size_t client_i, - PacketSavingConnection* server_conn, - QuicCryptoStream* server, - size_t server_i); - - // Returns the value for the tag |tag| in the tag value map of |message|. - static std::string GetValueForTag(const CryptoHandshakeMessage& message, - QuicTag tag); - - // Returns a new |ProofSource| that serves up test certificates. - static std::unique_ptr<ProofSource> ProofSourceForTesting(); - - // Identical to |ProofSourceForTesting|, with the addition of setting - // the |emit_expect_ct_header| field on the test certificates - // to be the value of |send_expect_ct_header|. - static std::unique_ptr<ProofSource> ProofSourceForTesting( - bool send_expect_ct_header); - - // Returns a new |ProofVerifier| that uses the QUIC testing root CA. - static std::unique_ptr<ProofVerifier> ProofVerifierForTesting(); - - // Returns a hash of the leaf test certificate. - static uint64_t LeafCertHashForTesting(); - - // Returns a |ProofVerifyContext| that must be used with the verifier - // returned by |ProofVerifierForTesting|. - static ProofVerifyContext* ProofVerifyContextForTesting(); - - // MockCommonCertSets returns a CommonCertSets that contains a single set with - // hash |hash|, consisting of the certificate |cert| at index |index|. - static CommonCertSets* MockCommonCertSets(base::StringPiece cert, - uint64_t hash, - uint32_t index); - - // Creates a minimal dummy reject message that will pass the client-config - // validation tests. This will include a server config, but no certs, proof - // source address token, or server nonce. - static void FillInDummyReject(CryptoHandshakeMessage* rej, - bool reject_is_stateless); - - // ParseTag returns a QuicTag from parsing |tagstr|. |tagstr| may either be - // in the format "EXMP" (i.e. ASCII format), or "#11223344" (an explicit hex - // format). It CHECK fails if there's a parse error. - static QuicTag ParseTag(const char* tagstr); - - // Message constructs a handshake message from a variable number of - // arguments. |message_tag| is passed to |ParseTag| and used as the tag of - // the resulting message. The arguments are taken in pairs and nullptr - // terminated. The first of each pair is the tag of a tag/value and is given - // as an argument to |ParseTag|. The second is the value of the tag/value - // pair and is either a hex dump, preceeded by a '#', or a raw value. - // - // Message( - // "CHLO", - // "NOCE", "#11223344", - // "SNI", "www.example.com", - // nullptr); - static CryptoHandshakeMessage Message(const char* message_tag, ...); - - // ChannelIDSourceForTesting returns a ChannelIDSource that generates keys - // deterministically based on the hostname given in the GetChannelIDKey call. - // This ChannelIDSource works in synchronous mode, i.e., its GetChannelIDKey - // method never returns QUIC_PENDING. - static ChannelIDSource* ChannelIDSourceForTesting(); - - // MovePackets parses crypto handshake messages from packet number - // |*inout_packet_index| through to the last packet (or until a packet fails - // to decrypt) and has |dest_stream| process them. |*inout_packet_index| is - // updated with an index one greater than the last packet processed. - static void MovePackets(PacketSavingConnection* source_conn, - size_t* inout_packet_index, - QuicCryptoStream* dest_stream, - PacketSavingConnection* dest_conn, - Perspective dest_perspective); - - // Return an inchoate CHLO with some basic tag value pairs. - static CryptoHandshakeMessage GenerateDefaultInchoateCHLO( - const QuicClock* clock, - QuicVersion version, - QuicCryptoServerConfig* crypto_config); - - // Takes a inchoate CHLO, returns a full CHLO in |out| which can pass - // |crypto_config|'s validation. - static void GenerateFullCHLO( - const CryptoHandshakeMessage& inchoate_chlo, - QuicCryptoServerConfig* crypto_config, - QuicSocketAddress server_addr, - QuicSocketAddress client_addr, - QuicVersion version, - const QuicClock* clock, - QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config, - QuicCompressedCertsCache* compressed_certs_cache, - CryptoHandshakeMessage* out); - - private: - static void CompareClientAndServerKeys(QuicCryptoClientStream* client, - QuicCryptoServerStream* server); - - // Return a CHLO nonce in hexadecimal. - static std::string GenerateClientNonceHex( - const QuicClock* clock, - QuicCryptoServerConfig* crypto_config); - - // Return a CHLO PUBS in hexadecimal. - static std::string GenerateClientPublicValuesHex(); - - DISALLOW_COPY_AND_ASSIGN(CryptoTestUtils); + // Runs pending callbacks from this source. If there is no pending + // callback, does nothing. + virtual void RunPendingCallbacks() = 0; }; +// FakeServerOptions bundles together a number of options for configuring the +// server in HandshakeWithFakeServer. +struct FakeServerOptions { + FakeServerOptions(); + ~FakeServerOptions(); + + // The Token Binding params that the server supports and will negotiate. + QuicTagVector token_binding_params; +}; + +// FakeClientOptions bundles together a number of options for configuring +// HandshakeWithFakeClient. +struct FakeClientOptions { + FakeClientOptions(); + ~FakeClientOptions(); + + // If channel_id_enabled is true then the client will attempt to send a + // ChannelID. + bool channel_id_enabled; + + // If channel_id_source_async is true then the client will use an async + // ChannelIDSource for testing. Ignored if channel_id_enabled is false. + bool channel_id_source_async; + + // The Token Binding params that the client supports and will negotiate. + QuicTagVector token_binding_params; +}; + +// returns: the number of client hellos that the client sent. +int HandshakeWithFakeServer(QuicConfig* server_quic_config, + MockQuicConnectionHelper* helper, + MockAlarmFactory* alarm_factory, + PacketSavingConnection* client_conn, + QuicCryptoClientStream* client, + const FakeServerOptions& options); + +// returns: the number of client hellos that the client sent. +int HandshakeWithFakeClient(MockQuicConnectionHelper* helper, + MockAlarmFactory* alarm_factory, + PacketSavingConnection* server_conn, + QuicCryptoServerStream* server, + const QuicServerId& server_id, + const FakeClientOptions& options); + +// SetupCryptoServerConfigForTest configures |crypto_config| +// with sensible defaults for testing. +void SetupCryptoServerConfigForTest(const QuicClock* clock, + QuicRandom* rand, + QuicCryptoServerConfig* crypto_config, + const FakeServerOptions& options); + +// CommunicateHandshakeMessages moves messages from |client| to |server| and +// back until |clients|'s handshake has completed. +void CommunicateHandshakeMessages(PacketSavingConnection* client_conn, + QuicCryptoStream* client, + PacketSavingConnection* server_conn, + QuicCryptoStream* server); + +// CommunicateHandshakeMessagesAndRunCallbacks moves messages from |client| +// to |server| and back until |client|'s handshake has completed. If +// |callback_source| is not nullptr, +// CommunicateHandshakeMessagesAndRunCallbacks also runs callbacks from +// |callback_source| between processing messages. +void CommunicateHandshakeMessagesAndRunCallbacks( + PacketSavingConnection* client_conn, + QuicCryptoStream* client, + PacketSavingConnection* server_conn, + QuicCryptoStream* server, + CallbackSource* callback_source); + +// AdvanceHandshake attempts to moves messages from |client| to |server| and +// |server| to |client|. Returns the number of messages moved. +std::pair<size_t, size_t> AdvanceHandshake(PacketSavingConnection* client_conn, + QuicCryptoStream* client, + size_t client_i, + PacketSavingConnection* server_conn, + QuicCryptoStream* server, + size_t server_i); + +// Returns the value for the tag |tag| in the tag value map of |message|. +std::string GetValueForTag(const CryptoHandshakeMessage& message, QuicTag tag); + +// Returns a new |ProofSource| that serves up test certificates. +std::unique_ptr<ProofSource> ProofSourceForTesting(); + +// Returns a new |ProofVerifier| that uses the QUIC testing root CA. +std::unique_ptr<ProofVerifier> ProofVerifierForTesting(); + +// Returns a hash of the leaf test certificate. +uint64_t LeafCertHashForTesting(); + +// Returns a |ProofVerifyContext| that must be used with the verifier +// returned by |ProofVerifierForTesting|. +ProofVerifyContext* ProofVerifyContextForTesting(); + +// MockCommonCertSets returns a CommonCertSets that contains a single set with +// hash |hash|, consisting of the certificate |cert| at index |index|. +CommonCertSets* MockCommonCertSets(base::StringPiece cert, + uint64_t hash, + uint32_t index); + +// Creates a minimal dummy reject message that will pass the client-config +// validation tests. This will include a server config, but no certs, proof +// source address token, or server nonce. +void FillInDummyReject(CryptoHandshakeMessage* rej, bool reject_is_stateless); + +// ParseTag returns a QuicTag from parsing |tagstr|. |tagstr| may either be +// in the format "EXMP" (i.e. ASCII format), or "#11223344" (an explicit hex +// format). It CHECK fails if there's a parse error. +QuicTag ParseTag(const char* tagstr); + +// Message constructs a CHLO message from a provided vector of tag/value pairs. +// The first of each pair is the tag of a tag/value and is given as an argument +// to |ParseTag|. The second is the value of the tag/value pair and is either a +// hex dump, preceeded by a '#', or a raw value. If minimum_size_bytes is +// provided then the message will be padded to this minimum size. +// +// CreateCHLO( +// {{"NOCE", "#11223344"}, +// {"SNI", "www.example.com"}}, +// optional_minimum_size_bytes); +CryptoHandshakeMessage CreateCHLO( + std::vector<std::pair<std::string, std::string>> tags_and_values); +CryptoHandshakeMessage CreateCHLO( + std::vector<std::pair<std::string, std::string>> tags_and_values, + int minimum_size_bytes); + +// ChannelIDSourceForTesting returns a ChannelIDSource that generates keys +// deterministically based on the hostname given in the GetChannelIDKey call. +// This ChannelIDSource works in synchronous mode, i.e., its GetChannelIDKey +// method never returns QUIC_PENDING. +ChannelIDSource* ChannelIDSourceForTesting(); + +// MovePackets parses crypto handshake messages from packet number +// |*inout_packet_index| through to the last packet (or until a packet fails +// to decrypt) and has |dest_stream| process them. |*inout_packet_index| is +// updated with an index one greater than the last packet processed. +void MovePackets(PacketSavingConnection* source_conn, + size_t* inout_packet_index, + QuicCryptoStream* dest_stream, + PacketSavingConnection* dest_conn, + Perspective dest_perspective); + +// Return an inchoate CHLO with some basic tag value pairs. +CryptoHandshakeMessage GenerateDefaultInchoateCHLO( + const QuicClock* clock, + QuicVersion version, + QuicCryptoServerConfig* crypto_config); + +// Takes a inchoate CHLO, returns a full CHLO in |out| which can pass +// |crypto_config|'s validation. +void GenerateFullCHLO( + const CryptoHandshakeMessage& inchoate_chlo, + QuicCryptoServerConfig* crypto_config, + QuicSocketAddress server_addr, + QuicSocketAddress client_addr, + QuicVersion version, + const QuicClock* clock, + QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config, + QuicCompressedCertsCache* compressed_certs_cache, + CryptoHandshakeMessage* out); + +void CompareClientAndServerKeys(QuicCryptoClientStream* client, + QuicCryptoServerStream* server); + +// Return a CHLO nonce in hexadecimal. +std::string GenerateClientNonceHex(const QuicClock* clock, + QuicCryptoServerConfig* crypto_config); + +// Return a CHLO PUBS in hexadecimal. +std::string GenerateClientPublicValuesHex(); + +} // namespace crypto_test_utils + } // namespace test } // namespace net
diff --git a/net/quic/test_tools/crypto_test_utils_test.cc b/net/quic/test_tools/crypto_test_utils_test.cc index 85069446..2349f1f 100644 --- a/net/quic/test_tools/crypto_test_utils_test.cc +++ b/net/quic/test_tools/crypto_test_utils_test.cc
@@ -112,7 +112,7 @@ MockClock clock; QuicCryptoServerConfig crypto_config( QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), - CryptoTestUtils::ProofSourceForTesting()); + crypto_test_utils::ProofSourceForTesting()); QuicSocketAddress server_addr; QuicSocketAddress client_addr(QuicIpAddress::Loopback4(), 1); QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config( @@ -148,23 +148,19 @@ "#" + QuicTextUtils::HexEncode(public_value, sizeof(public_value)); QuicVersion version(AllSupportedVersions().front()); - // clang-format off - CryptoHandshakeMessage inchoate_chlo = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "AEAD", "AESG", - "KEXS", "C255", - "COPT", "SREJ", - "PUBS", pub_hex.c_str(), - "NONC", nonce_hex.c_str(), - "VER\0", QuicTagToString(QuicVersionToQuicTag(version)).c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage inchoate_chlo = crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"COPT", "SREJ"}, + {"PUBS", pub_hex}, + {"NONC", nonce_hex}, + {"VER\0", QuicTagToString(QuicVersionToQuicTag(version))}}, + kClientHelloMinimumSize); - CryptoTestUtils::GenerateFullCHLO(inchoate_chlo, &crypto_config, server_addr, - client_addr, version, &clock, signed_config, - &compressed_certs_cache, &full_chlo); + crypto_test_utils::GenerateFullCHLO( + inchoate_chlo, &crypto_config, server_addr, client_addr, version, &clock, + signed_config, &compressed_certs_cache, &full_chlo); // Verify that full_chlo can pass crypto_config's verification. ShloVerifier shlo_verifier(&crypto_config, server_addr, client_addr, &clock, signed_config, &compressed_certs_cache);
diff --git a/net/quic/test_tools/failing_proof_source.cc b/net/quic/test_tools/failing_proof_source.cc index 53b69e1..a45bf52 100644 --- a/net/quic/test_tools/failing_proof_source.cc +++ b/net/quic/test_tools/failing_proof_source.cc
@@ -7,18 +7,6 @@ namespace net { namespace test { -bool FailingProofSource::GetProof( - const QuicSocketAddress& server_address, - const std::string& hostname, - const std::string& server_config, - QuicVersion quic_version, - base::StringPiece chlo_hash, - const QuicTagVector& connection_options, - QuicReferenceCountedPointer<ProofSource::Chain>* out_chain, - QuicCryptoProof* out_proof) { - return false; -} - void FailingProofSource::GetProof(const QuicSocketAddress& server_address, const std::string& hostname, const std::string& server_config,
diff --git a/net/quic/test_tools/failing_proof_source.h b/net/quic/test_tools/failing_proof_source.h index 67aa44e..dfc72fe 100644 --- a/net/quic/test_tools/failing_proof_source.h +++ b/net/quic/test_tools/failing_proof_source.h
@@ -12,15 +12,6 @@ class FailingProofSource : public ProofSource { public: - bool GetProof(const QuicSocketAddress& server_address, - const std::string& hostname, - const std::string& server_config, - QuicVersion quic_version, - base::StringPiece chlo_hash, - const QuicTagVector& connection_options, - QuicReferenceCountedPointer<ProofSource::Chain>* out_chain, - QuicCryptoProof* out_proof) override; - void GetProof(const QuicSocketAddress& server_address, const std::string& hostname, const std::string& server_config,
diff --git a/net/quic/test_tools/fake_proof_source.cc b/net/quic/test_tools/fake_proof_source.cc index e4360195..0eea145 100644 --- a/net/quic/test_tools/fake_proof_source.cc +++ b/net/quic/test_tools/fake_proof_source.cc
@@ -12,7 +12,7 @@ namespace test { FakeProofSource::FakeProofSource() - : delegate_(CryptoTestUtils::ProofSourceForTesting()) {} + : delegate_(crypto_test_utils::ProofSourceForTesting()) {} FakeProofSource::~FakeProofSource() {} @@ -42,21 +42,6 @@ active_ = true; } -bool FakeProofSource::GetProof( - const QuicSocketAddress& server_address, - const string& hostname, - const string& server_config, - QuicVersion quic_version, - StringPiece chlo_hash, - const QuicTagVector& connection_options, - QuicReferenceCountedPointer<ProofSource::Chain>* out_chain, - QuicCryptoProof* out_proof) { - QUIC_LOG(WARNING) << "Synchronous GetProof called"; - return delegate_->GetProof(server_address, hostname, server_config, - quic_version, chlo_hash, connection_options, - out_chain, out_proof); -} - void FakeProofSource::GetProof( const QuicSocketAddress& server_address, const string& hostname, @@ -66,16 +51,11 @@ const QuicTagVector& connection_options, std::unique_ptr<ProofSource::Callback> callback) { if (!active_) { - QuicReferenceCountedPointer<Chain> chain; - QuicCryptoProof proof; - const bool ok = - GetProof(server_address, hostname, server_config, quic_version, - chlo_hash, connection_options, &chain, &proof); - callback->Run(ok, chain, proof, /* details = */ nullptr); + delegate_->GetProof(server_address, hostname, server_config, quic_version, + chlo_hash, connection_options, std::move(callback)); return; } - QUIC_LOG(WARNING) << "Asynchronous GetProof called"; params_.push_back(Params{server_address, hostname, server_config, quic_version, chlo_hash.as_string(), connection_options, std::move(callback)}); @@ -88,16 +68,14 @@ void FakeProofSource::InvokePendingCallback(int n) { CHECK(NumPendingCallbacks() > n); - const Params& params = params_[n]; + Params& params = params_[n]; - QuicReferenceCountedPointer<ProofSource::Chain> chain; - QuicCryptoProof proof; - const bool ok = delegate_->GetProof( - params.server_address, params.hostname, params.server_config, - params.quic_version, params.chlo_hash, params.connection_options, &chain, - &proof); + // Note: relies on the callback being invoked synchronously + delegate_->GetProof(params.server_address, params.hostname, + params.server_config, params.quic_version, + params.chlo_hash, params.connection_options, + std::move(params.callback)); - params.callback->Run(ok, chain, proof, /* details = */ nullptr); auto it = params_.begin() + n; params_.erase(it); }
diff --git a/net/quic/test_tools/fake_proof_source.h b/net/quic/test_tools/fake_proof_source.h index 776466d..b6713f3 100644 --- a/net/quic/test_tools/fake_proof_source.h +++ b/net/quic/test_tools/fake_proof_source.h
@@ -30,14 +30,6 @@ void Activate(); // ProofSource interface - bool GetProof(const QuicSocketAddress& server_address, - const std::string& hostname, - const std::string& server_config, - QuicVersion quic_version, - base::StringPiece chlo_hash, - const QuicTagVector& connection_options, - QuicReferenceCountedPointer<ProofSource::Chain>* out_chain, - QuicCryptoProof* out_proof) override; void GetProof(const QuicSocketAddress& server_address, const std::string& hostname, const std::string& server_config,
diff --git a/net/quic/test_tools/quic_crypto_server_config_peer.cc b/net/quic/test_tools/quic_crypto_server_config_peer.cc index d9a47f7..fa2b30c 100644 --- a/net/quic/test_tools/quic_crypto_server_config_peer.cc +++ b/net/quic/test_tools/quic_crypto_server_config_peer.cc
@@ -97,44 +97,19 @@ return server_config_->NewServerNonce(rand, now); } -void QuicCryptoServerConfigPeer::CheckConfigs(const char* server_config_id1, - ...) { - va_list ap; - va_start(ap, server_config_id1); - - std::vector<std::pair<ServerConfigID, bool>> expected; - bool first = true; - for (;;) { - const char* server_config_id; - if (first) { - server_config_id = server_config_id1; - first = false; - } else { - server_config_id = va_arg(ap, const char*); - } - - if (!server_config_id) { - break; - } - - // varargs will promote the value to an int so we have to read that from - // the stack and cast down. - const bool is_primary = static_cast<bool>(va_arg(ap, int)); - expected.push_back(std::make_pair(server_config_id, is_primary)); - } - - va_end(ap); - +void QuicCryptoServerConfigPeer::CheckConfigs( + std::vector<std::pair<string, bool>> expected_ids_and_status) { QuicReaderMutexLock locked(&server_config_->configs_lock_); - ASSERT_EQ(expected.size(), server_config_->configs_.size()) << ConfigsDebug(); + ASSERT_EQ(expected_ids_and_status.size(), server_config_->configs_.size()) + << ConfigsDebug(); for (const std::pair< const ServerConfigID, QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>>& i : server_config_->configs_) { bool found = false; - for (std::pair<ServerConfigID, bool>& j : expected) { + for (std::pair<ServerConfigID, bool>& j : expected_ids_and_status) { if (i.first == j.first && i.second->is_primary == j.second) { found = true; j.first.clear();
diff --git a/net/quic/test_tools/quic_crypto_server_config_peer.h b/net/quic/test_tools/quic_crypto_server_config_peer.h index 310be87..facde4ef 100644 --- a/net/quic/test_tools/quic_crypto_server_config_peer.h +++ b/net/quic/test_tools/quic_crypto_server_config_peer.h
@@ -60,20 +60,20 @@ std::string NewServerNonce(QuicRandom* rand, QuicWallTime now) const; // CheckConfigs compares the state of the Configs in |server_config_| to the - // description given as arguments. The arguments are given as - // nullptr-terminated pairs. The first of each pair is the server config ID of - // a Config. The second is a boolean describing whether the config is the - // primary. For example: - // CheckConfigs(nullptr); // checks that no Configs are loaded. + // description given as arguments. + // The first of each pair is the server config ID of a Config. The second is a + // boolean describing whether the config is the primary. For example: + // CheckConfigs(std::vector<std::pair<ServerConfigID, bool>>()); // checks + // that no Configs are loaded. // // // Checks that exactly three Configs are loaded with the given IDs and // // status. // CheckConfigs( - // "id1", false, - // "id2", true, - // "id3", false, - // nullptr); - void CheckConfigs(const char* server_config_id1, ...); + // {{"id1", false}, + // {"id2", true}, + // {"id3", false}}); + void CheckConfigs( + std::vector<std::pair<ServerConfigID, bool>> expected_ids_and_status); // ConfigsDebug returns a string that contains debugging information about // the set of Configs loaded in |server_config_| and their status.
diff --git a/net/quic/test_tools/quic_stream_peer.cc b/net/quic/test_tools/quic_stream_peer.cc index b35ec1a12..f1362c98 100644 --- a/net/quic/test_tools/quic_stream_peer.cc +++ b/net/quic/test_tools/quic_stream_peer.cc
@@ -93,9 +93,14 @@ } // static -net::QuicStreamSequencer* QuicStreamPeer::sequencer(QuicStream* stream) { +QuicStreamSequencer* QuicStreamPeer::sequencer(QuicStream* stream) { return &(stream->sequencer_); } +// static +QuicSession* QuicStreamPeer::session(QuicStream* stream) { + return stream->session(); +} + } // namespace test } // namespace net
diff --git a/net/quic/test_tools/quic_stream_peer.h b/net/quic/test_tools/quic_stream_peer.h index 3d9b4f4..aa634c5 100644 --- a/net/quic/test_tools/quic_stream_peer.h +++ b/net/quic/test_tools/quic_stream_peer.h
@@ -15,6 +15,7 @@ namespace net { class QuicStream; +class QuicSession; namespace test { @@ -44,7 +45,8 @@ bool fin, QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener); - static net::QuicStreamSequencer* sequencer(QuicStream* stream); + static QuicStreamSequencer* sequencer(QuicStream* stream); + static QuicSession* session(QuicStream* stream); private: DISALLOW_COPY_AND_ASSIGN(QuicStreamPeer);
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc index eb07001..9b30937 100644 --- a/net/quic/test_tools/quic_test_utils.cc +++ b/net/quic/test_tools/quic_test_utils.cc
@@ -461,7 +461,7 @@ QuicCryptoClientConfig* crypto_config) : QuicClientSessionBase(connection, &push_promise_index_, config) { crypto_stream_.reset(new QuicCryptoClientStream( - server_id, this, CryptoTestUtils::ProofVerifyContextForTesting(), + server_id, this, crypto_test_utils::ProofVerifyContextForTesting(), crypto_config, this)); Initialize(); } @@ -645,7 +645,7 @@ EXPECT_TRUE(packet != nullptr); char* buffer = new char[kMaxPacketSize]; size_t encrypted_length = framer.EncryptPayload( - ENCRYPTION_NONE, path_id, packet_number, *packet, buffer, kMaxPacketSize); + ENCRYPTION_NONE, packet_number, *packet, buffer, kMaxPacketSize); EXPECT_NE(0u, encrypted_length); return new QuicEncryptedPacket(buffer, encrypted_length, true); } @@ -699,7 +699,7 @@ char* buffer = new char[kMaxPacketSize]; size_t encrypted_length = framer.EncryptPayload( - ENCRYPTION_NONE, path_id, packet_number, *packet, buffer, kMaxPacketSize); + ENCRYPTION_NONE, packet_number, *packet, buffer, kMaxPacketSize); EXPECT_NE(0u, encrypted_length); return new QuicEncryptedPacket(buffer, encrypted_length, true); }
diff --git a/net/spdy/buffered_spdy_framer.cc b/net/spdy/buffered_spdy_framer.cc index fbedb84..b0fbb96 100644 --- a/net/spdy/buffered_spdy_framer.cc +++ b/net/spdy/buffered_spdy_framer.cc
@@ -22,8 +22,6 @@ BufferedSpdyFramer::BufferedSpdyFramer() : spdy_framer_(SpdyFramer::ENABLE_COMPRESSION), visitor_(NULL), - header_buffer_valid_(false), - header_stream_id_(SpdyFramer::kInvalidStream), frames_received_(0) {} BufferedSpdyFramer::~BufferedSpdyFramer() { @@ -65,14 +63,13 @@ } control_frame_fields_->fin = fin; - InitHeaderStreaming(stream_id); + DCHECK_NE(stream_id, SpdyFramer::kInvalidStream); } void BufferedSpdyFramer::OnDataFrameHeader(SpdyStreamId stream_id, size_t length, bool fin) { frames_received_++; - header_stream_id_ = stream_id; visitor_->OnDataFrameHeader(stream_id, length, fin); } @@ -101,6 +98,7 @@ if (coalescer_->error_seen()) { visitor_->OnStreamError(stream_id, "Could not parse Spdy Control Frame Header."); + control_frame_fields_.reset(); return; } DCHECK(control_frame_fields_.get()); @@ -189,7 +187,7 @@ control_frame_fields_->stream_id = stream_id; control_frame_fields_->promised_stream_id = promised_stream_id; - InitHeaderStreaming(stream_id); + DCHECK_NE(stream_id, SpdyFramer::kInvalidStream); } void BufferedSpdyFramer::OnAltSvc( @@ -334,11 +332,4 @@ return spdy_framer_.GetHighestPriority(); } -void BufferedSpdyFramer::InitHeaderStreaming(SpdyStreamId stream_id) { - header_buffer_.clear(); - header_buffer_valid_ = true; - header_stream_id_ = stream_id; - DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream); -} - } // namespace net
diff --git a/net/spdy/buffered_spdy_framer.h b/net/spdy/buffered_spdy_framer.h index ffd03a1..3c75122 100644 --- a/net/spdy/buffered_spdy_framer.h +++ b/net/spdy/buffered_spdy_framer.h
@@ -236,15 +236,9 @@ int frames_received() const { return frames_received_; } private: - void InitHeaderStreaming(SpdyStreamId stream_id); - SpdyFramer spdy_framer_; BufferedSpdyFramerVisitorInterface* visitor_; - // Header block streaming state: - std::string header_buffer_; - bool header_buffer_valid_; - SpdyStreamId header_stream_id_; int frames_received_; // Collection of fields from control frames that we need to
diff --git a/net/spdy/buffered_spdy_framer_unittest.cc b/net/spdy/buffered_spdy_framer_unittest.cc index aba9a5c9..e0a6414 100644 --- a/net/spdy/buffered_spdy_framer_unittest.cc +++ b/net/spdy/buffered_spdy_framer_unittest.cc
@@ -127,10 +127,10 @@ } // Convenience function which runs a framer simulation with particular input. - void SimulateInFramer(const unsigned char* input, size_t size) { + void SimulateInFramer(const SpdySerializedFrame& frame) { + const char* input_ptr = frame.data(); + size_t input_remaining = frame.size(); buffered_spdy_framer_.set_visitor(this); - size_t input_remaining = size; - const char* input_ptr = reinterpret_cast<const char*>(input); while (input_remaining > 0 && buffered_spdy_framer_.spdy_framer_error() == SpdyFramer::SPDY_NO_ERROR) { @@ -187,9 +187,7 @@ SpdySerializedFrame control_frame(framer.SerializeSettings(settings_ir)); TestBufferedSpdyVisitor visitor; - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(control_frame.data()), - control_frame.size()); + visitor.SimulateInFramer(control_frame); EXPECT_EQ(0, visitor.error_count_); EXPECT_EQ(2, visitor.setting_count_); } @@ -207,9 +205,7 @@ EXPECT_TRUE(control_frame); TestBufferedSpdyVisitor visitor; - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(control_frame.get()->data()), - control_frame.get()->size()); + visitor.SimulateInFramer(*control_frame); EXPECT_EQ(1, visitor.error_count_); EXPECT_EQ(0, visitor.headers_frame_count_); @@ -217,6 +213,29 @@ EXPECT_EQ(SpdyHeaderBlock(), visitor.headers_); } +TEST_F(BufferedSpdyFramerTest, ValidHeadersAfterInvalidHeaders) { + SpdyHeaderBlock headers; + headers["invalid"] = "\r\n\r\n"; + + SpdyHeaderBlock headers2; + headers["alpha"] = "beta"; + + SpdyTestUtil spdy_test_util; + SpdySerializedFrame headers_frame( + spdy_test_util.ConstructSpdyReply(1, std::move(headers))); + SpdySerializedFrame headers_frame2( + spdy_test_util.ConstructSpdyReply(2, std::move(headers2))); + + TestBufferedSpdyVisitor visitor; + visitor.SimulateInFramer(headers_frame); + EXPECT_EQ(1, visitor.error_count_); + EXPECT_EQ(0, visitor.headers_frame_count_); + + visitor.SimulateInFramer(headers_frame2); + EXPECT_EQ(1, visitor.error_count_); + EXPECT_EQ(1, visitor.headers_frame_count_); +} + TEST_F(BufferedSpdyFramerTest, ReadHeadersHeaderBlock) { SpdyHeaderBlock headers; headers["alpha"] = "beta"; @@ -230,9 +249,7 @@ EXPECT_TRUE(control_frame.get() != NULL); TestBufferedSpdyVisitor visitor; - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(control_frame.get()->data()), - control_frame.get()->size()); + visitor.SimulateInFramer(*control_frame); EXPECT_EQ(0, visitor.error_count_); EXPECT_EQ(1, visitor.headers_frame_count_); EXPECT_EQ(0, visitor.push_promise_frame_count_); @@ -249,9 +266,7 @@ EXPECT_TRUE(control_frame.get() != NULL); TestBufferedSpdyVisitor visitor; - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(control_frame.get()->data()), - control_frame.get()->size()); + visitor.SimulateInFramer(*control_frame); EXPECT_EQ(0, visitor.error_count_); EXPECT_EQ(0, visitor.headers_frame_count_); EXPECT_EQ(1, visitor.push_promise_frame_count_); @@ -266,9 +281,7 @@ framer.CreateGoAway(2u, ERROR_CODE_FRAME_SIZE_ERROR, "foo")); TestBufferedSpdyVisitor visitor; - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(goaway_frame.get()->data()), - goaway_frame.get()->size()); + visitor.SimulateInFramer(*goaway_frame); EXPECT_EQ(0, visitor.error_count_); EXPECT_EQ(1, visitor.goaway_count_); EXPECT_EQ(2u, visitor.goaway_last_accepted_stream_id_); @@ -289,9 +302,7 @@ SpdySerializedFrame altsvc_frame(framer.SerializeFrame(altsvc_ir)); TestBufferedSpdyVisitor visitor; - visitor.SimulateInFramer( - reinterpret_cast<unsigned char*>(altsvc_frame.data()), - altsvc_frame.size()); + visitor.SimulateInFramer(altsvc_frame); EXPECT_EQ(0, visitor.error_count_); EXPECT_EQ(1, visitor.altsvc_count_); EXPECT_EQ(altsvc_stream_id, visitor.altsvc_stream_id_);
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc index ca037280..e856c55d 100644 --- a/net/spdy/spdy_network_transaction_unittest.cc +++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -509,6 +509,37 @@ VerifyStreamsClosed(helper); } + void RunBrokenPushTest(SequencedSocketData* data, int expected_rv) { + NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, + NetLogWithSource(), nullptr); + helper.RunPreTestSetup(); + helper.AddData(data); + + HttpNetworkTransaction* trans = helper.trans(); + + // Start the transaction with basic parameters. + TestCompletionCallback callback; + int rv = trans->Start(&CreateGetRequest(), callback.callback(), + NetLogWithSource()); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + rv = callback.WaitForResult(); + EXPECT_EQ(expected_rv, rv); + + // Finish async network reads/writes. + base::RunLoop().RunUntilIdle(); + + // Verify that we consumed all test data. + EXPECT_TRUE(data->AllReadDataConsumed()); + EXPECT_TRUE(data->AllWriteDataConsumed()); + + if (expected_rv == OK) { + // Expected main request to succeed, even if push failed. + HttpResponseInfo response = *trans->GetResponseInfo(); + EXPECT_TRUE(response.headers); + EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine()); + } + } + static void DeleteSessionCallback(NormalSpdyTransactionHelper* helper, int result) { helper->ResetTrans(); @@ -2861,6 +2892,37 @@ EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine()); } +TEST_F(SpdyNetworkTransactionTest, ServerPushInvalidUrl) { + // Coverage on how a non-empty invalid GURL in a PUSH_PROMISE is handled. + SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); + SpdySerializedFrame req( + spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true)); + + // Can't use ConstructSpdyPush here since it wants to parse a URL and + // split it into the appropriate :header pieces. So we have to hand-fill + // those pieces in. + SpdyFramer response_spdy_framer(SpdyFramer::ENABLE_COMPRESSION); + SpdyHeaderBlock push_promise_header_block; + push_promise_header_block[spdy_util_.GetHostKey()] = ""; + push_promise_header_block[spdy_util_.GetSchemeKey()] = ""; + push_promise_header_block[spdy_util_.GetPathKey()] = "/index.html"; + + SpdyPushPromiseIR push_promise(1, 2, std::move(push_promise_header_block)); + SpdySerializedFrame push_promise_frame( + response_spdy_framer.SerializeFrame(push_promise)); + + SpdySerializedFrame stream2_rst( + spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_PROTOCOL_ERROR)); + + MockWrite writes[] = {CreateMockWrite(req, 0), + CreateMockWrite(stream2_rst, 2)}; + MockRead reads[] = { + CreateMockRead(push_promise_frame, 1), MockRead(ASYNC, 0, 3) /* EOF */ + }; + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); + RunBrokenPushTest(&data, ERR_CONNECTION_CLOSED); +} + TEST_F(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID0) { SpdySerializedFrame stream1_syn( spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); @@ -2877,35 +2939,8 @@ MockRead reads[] = { CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2), }; - SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); - NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, - NetLogWithSource(), nullptr); - - helper.RunPreTestSetup(); - helper.AddData(&data); - - HttpNetworkTransaction* trans = helper.trans(); - - // Start the transaction with basic parameters. - TestCompletionCallback callback; - int rv = trans->Start(&CreateGetRequest(), callback.callback(), - NetLogWithSource()); - EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); - rv = callback.WaitForResult(); - EXPECT_THAT(rv, IsOk()); - - // Finish async network reads/writes. - base::RunLoop().RunUntilIdle(); - - // Verify that we consumed all test data. - EXPECT_TRUE(data.AllReadDataConsumed()); - EXPECT_TRUE(data.AllWriteDataConsumed()); - - // Verify the response headers. - HttpResponseInfo response = *trans->GetResponseInfo(); - EXPECT_TRUE(response.headers); - EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine()); + RunBrokenPushTest(&data, OK); } TEST_F(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID9) { @@ -2929,33 +2964,7 @@ }; SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); - NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, - NetLogWithSource(), nullptr); - - helper.RunPreTestSetup(); - helper.AddData(&data); - - HttpNetworkTransaction* trans = helper.trans(); - - // Start the transaction with basic parameters. - TestCompletionCallback callback; - int rv = trans->Start(&CreateGetRequest(), callback.callback(), - NetLogWithSource()); - EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); - rv = callback.WaitForResult(); - EXPECT_THAT(rv, IsOk()); - - // Finish async network reads/writes. - base::RunLoop().RunUntilIdle(); - - // Verify that we consumed all test data. - EXPECT_TRUE(data.AllReadDataConsumed()); - EXPECT_TRUE(data.AllWriteDataConsumed()); - - // Verify the response headers. - HttpResponseInfo response = *trans->GetResponseInfo(); - EXPECT_TRUE(response.headers); - EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine()); + RunBrokenPushTest(&data, OK); } TEST_F(SpdyNetworkTransactionTest, ServerPushNoURL) { @@ -2982,33 +2991,7 @@ }; SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); - NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, - NetLogWithSource(), nullptr); - - helper.RunPreTestSetup(); - helper.AddData(&data); - - HttpNetworkTransaction* trans = helper.trans(); - - // Start the transaction with basic parameters. - TestCompletionCallback callback; - int rv = trans->Start(&CreateGetRequest(), callback.callback(), - NetLogWithSource()); - EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); - rv = callback.WaitForResult(); - EXPECT_THAT(rv, IsOk()); - - // Finish async network reads/writes. - base::RunLoop().RunUntilIdle(); - - // Verify that we consumed all test data. - EXPECT_TRUE(data.AllReadDataConsumed()); - EXPECT_TRUE(data.AllWriteDataConsumed()); - - // Verify the response headers. - HttpResponseInfo response = *trans->GetResponseInfo(); - EXPECT_TRUE(response.headers); - EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine()); + RunBrokenPushTest(&data, OK); } // PUSH_PROMISE on a server-initiated stream should trigger GOAWAY.
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc index 92b8f5f..2e3a31a 100644 --- a/net/spdy/spdy_session.cc +++ b/net/spdy/spdy_session.cc
@@ -276,8 +276,7 @@ base::StringPiece debug_data, NetLogCaptureMode capture_mode) { auto dict = base::MakeUnique<base::DictionaryValue>(); - dict->SetInteger("last_accepted_stream_id", - static_cast<int>(last_stream_id)); + dict->SetInteger("last_accepted_stream_id", static_cast<int>(last_stream_id)); dict->SetInteger("active_streams", active_streams); dict->SetInteger("unclaimed_streams", unclaimed_streams); dict->SetString( @@ -342,7 +341,8 @@ // Helper function to return the total size of an array of objects // with .size() member functions. -template <typename T, size_t N> size_t GetTotalSize(const T (&arr)[N]) { +template <typename T, size_t N> +size_t GetTotalSize(const T (&arr)[N]) { size_t total_size = 0; for (size_t i = 0; i < N; ++i) { total_size += arr[i].size(); @@ -676,7 +676,7 @@ if (ssl_info.channel_id_sent && ChannelIDService::GetDomainForHost(new_hostname) != - ChannelIDService::GetDomainForHost(old_hostname)) { + ChannelIDService::GetDomainForHost(old_hostname)) { return false; } @@ -776,7 +776,8 @@ net_log_.BeginEvent( NetLogEventType::HTTP2_SESSION, base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair())); - next_unclaimed_push_stream_sweep_time_ = time_func_() + + next_unclaimed_push_stream_sweep_time_ = + time_func_() + base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds); DCHECK(base::ContainsKey(initial_settings_, SETTINGS_HEADER_TABLE_SIZE)); @@ -801,60 +802,6 @@ net_log_.EndEvent(NetLogEventType::HTTP2_SESSION); } -void SpdySession::InitializeWithSocket( - std::unique_ptr<ClientSocketHandle> connection, - SpdySessionPool* pool, - bool is_secure) { - CHECK(!in_io_loop_); - DCHECK_EQ(availability_state_, STATE_AVAILABLE); - DCHECK_EQ(read_state_, READ_STATE_DO_READ); - DCHECK_EQ(write_state_, WRITE_STATE_IDLE); - DCHECK(!connection_); - - // TODO(akalin): Check connection->is_initialized() instead. This - // requires re-working CreateFakeSpdySession(), though. - DCHECK(connection->socket()); - - connection_ = std::move(connection); - is_secure_ = is_secure; - - session_send_window_size_ = kDefaultInitialWindowSize; - session_recv_window_size_ = kDefaultInitialWindowSize; - - buffered_spdy_framer_.reset(new BufferedSpdyFramer()); - buffered_spdy_framer_->set_visitor(this); - buffered_spdy_framer_->set_debug_visitor(this); - buffered_spdy_framer_->UpdateHeaderDecoderTableSize(max_header_table_size_); - - net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_INITIALIZED, - base::Bind(&NetLogSpdyInitializedCallback, - connection_->socket()->NetLog().source())); - - DCHECK_EQ(availability_state_, STATE_AVAILABLE); - connection_->AddHigherLayeredPool(this); - if (enable_sending_initial_data_) - SendInitialData(); - pool_ = pool; - - // Bootstrap the read loop. - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&SpdySession::PumpReadLoop, weak_factory_.GetWeakPtr(), - READ_STATE_DO_READ, OK)); -} - -bool SpdySession::VerifyDomainAuthentication(const std::string& domain) { - if (availability_state_ == STATE_DRAINING) - return false; - - SSLInfo ssl_info; - if (!GetSSLInfo(&ssl_info)) - return true; // This is not a secure session, so all domains are okay. - - return CanPool(transport_security_state_, ssl_info, - host_port_pair().host(), domain); -} - int SpdySession::GetPushStream(const GURL& url, RequestPriority priority, SpdyStream** stream, @@ -908,184 +855,58 @@ unclaimed_pushed_streams_.erase(unclaimed_it); } -// {,Try}CreateStream() can be called with |in_io_loop_| set if a stream is -// being created in response to another being closed due to received data. +void SpdySession::InitializeWithSocket( + std::unique_ptr<ClientSocketHandle> connection, + SpdySessionPool* pool, + bool is_secure) { + CHECK(!in_io_loop_); + DCHECK_EQ(availability_state_, STATE_AVAILABLE); + DCHECK_EQ(read_state_, READ_STATE_DO_READ); + DCHECK_EQ(write_state_, WRITE_STATE_IDLE); + DCHECK(!connection_); -int SpdySession::TryCreateStream( - const base::WeakPtr<SpdyStreamRequest>& request, - base::WeakPtr<SpdyStream>* stream) { - DCHECK(request); + // TODO(akalin): Check connection->is_initialized() instead. This + // requires re-working CreateFakeSpdySession(), though. + DCHECK(connection->socket()); - if (availability_state_ == STATE_GOING_AWAY) - return ERR_FAILED; + connection_ = std::move(connection); + is_secure_ = is_secure; + session_send_window_size_ = kDefaultInitialWindowSize; + session_recv_window_size_ = kDefaultInitialWindowSize; + + buffered_spdy_framer_.reset(new BufferedSpdyFramer()); + buffered_spdy_framer_->set_visitor(this); + buffered_spdy_framer_->set_debug_visitor(this); + buffered_spdy_framer_->UpdateHeaderDecoderTableSize(max_header_table_size_); + + net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_INITIALIZED, + base::Bind(&NetLogSpdyInitializedCallback, + connection_->socket()->NetLog().source())); + + DCHECK_EQ(availability_state_, STATE_AVAILABLE); + connection_->AddHigherLayeredPool(this); + if (enable_sending_initial_data_) + SendInitialData(); + pool_ = pool; + + // Bootstrap the read loop. + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(&SpdySession::PumpReadLoop, weak_factory_.GetWeakPtr(), + READ_STATE_DO_READ, OK)); +} + +bool SpdySession::VerifyDomainAuthentication(const std::string& domain) { if (availability_state_ == STATE_DRAINING) - return ERR_CONNECTION_CLOSED; - - if ((active_streams_.size() + created_streams_.size() - num_pushed_streams_ < - max_concurrent_streams_)) { - return CreateStream(*request, stream); - } - - if (net_log().IsCapturing()) { - net_log().AddEvent( - NetLogEventType::HTTP2_SESSION_STALLED_MAX_STREAMS, - base::Bind(&NetLogSpdySessionStalledCallback, active_streams_.size(), - created_streams_.size(), num_pushed_streams_, - max_concurrent_streams_, request->url().spec())); - } - RequestPriority priority = request->priority(); - CHECK_GE(priority, MINIMUM_PRIORITY); - CHECK_LE(priority, MAXIMUM_PRIORITY); - pending_create_stream_queues_[priority].push_back(request); - return ERR_IO_PENDING; -} - -int SpdySession::CreateStream(const SpdyStreamRequest& request, - base::WeakPtr<SpdyStream>* stream) { - DCHECK_GE(request.priority(), MINIMUM_PRIORITY); - DCHECK_LE(request.priority(), MAXIMUM_PRIORITY); - - if (availability_state_ == STATE_GOING_AWAY) - return ERR_FAILED; - - if (availability_state_ == STATE_DRAINING) - return ERR_CONNECTION_CLOSED; - - DCHECK(connection_->socket()); - UMA_HISTOGRAM_BOOLEAN("Net.SpdySession.CreateStreamWithSocketConnected", - connection_->socket()->IsConnected()); - if (!connection_->socket()->IsConnected()) { - DoDrainSession( - ERR_CONNECTION_CLOSED, - "Tried to create SPDY stream for a closed socket connection."); - return ERR_CONNECTION_CLOSED; - } - - std::unique_ptr<SpdyStream> new_stream( - new SpdyStream(request.type(), GetWeakPtr(), request.url(), - request.priority(), stream_initial_send_window_size_, - stream_max_recv_window_size_, request.net_log())); - *stream = new_stream->GetWeakPtr(); - InsertCreatedStream(std::move(new_stream)); - - return OK; -} - -void SpdySession::CancelStreamRequest( - const base::WeakPtr<SpdyStreamRequest>& request) { - DCHECK(request); - RequestPriority priority = request->priority(); - CHECK_GE(priority, MINIMUM_PRIORITY); - CHECK_LE(priority, MAXIMUM_PRIORITY); - -#if DCHECK_IS_ON() - // |request| should not be in a queue not matching its priority. - for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) { - if (priority == i) - continue; - PendingStreamRequestQueue* queue = &pending_create_stream_queues_[i]; - DCHECK(std::find_if(queue->begin(), - queue->end(), - RequestEquals(request)) == queue->end()); - } -#endif - - PendingStreamRequestQueue* queue = - &pending_create_stream_queues_[priority]; - // Remove |request| from |queue| while preserving the order of the - // other elements. - PendingStreamRequestQueue::iterator it = - std::find_if(queue->begin(), queue->end(), RequestEquals(request)); - // The request may already be removed if there's a - // CompleteStreamRequest() in flight. - if (it != queue->end()) { - it = queue->erase(it); - // |request| should be in the queue at most once, and if it is - // present, should not be pending completion. - DCHECK(std::find_if(it, queue->end(), RequestEquals(request)) == - queue->end()); - } -} - -base::WeakPtr<SpdyStreamRequest> SpdySession::GetNextPendingStreamRequest() { - for (int j = MAXIMUM_PRIORITY; j >= MINIMUM_PRIORITY; --j) { - if (pending_create_stream_queues_[j].empty()) - continue; - - base::WeakPtr<SpdyStreamRequest> pending_request = - pending_create_stream_queues_[j].front(); - DCHECK(pending_request); - pending_create_stream_queues_[j].pop_front(); - return pending_request; - } - return base::WeakPtr<SpdyStreamRequest>(); -} - -void SpdySession::ProcessPendingStreamRequests() { - size_t max_requests_to_process = - max_concurrent_streams_ - - (active_streams_.size() + created_streams_.size()); - for (size_t i = 0; i < max_requests_to_process; ++i) { - base::WeakPtr<SpdyStreamRequest> pending_request = - GetNextPendingStreamRequest(); - if (!pending_request) - break; - - // Note that this post can race with other stream creations, and it's - // possible that the un-stalled stream will be stalled again if it loses. - // TODO(jgraettinger): Provide stronger ordering guarantees. - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&SpdySession::CompleteStreamRequest, - weak_factory_.GetWeakPtr(), pending_request)); - } -} - -void SpdySession::AddPooledAlias(const SpdySessionKey& alias_key) { - pooled_aliases_.insert(alias_key); -} - -bool SpdySession::HasAcceptableTransportSecurity() const { - // If we're not even using TLS, we have no standards to meet. - if (!is_secure_) { - return true; - } + return false; SSLInfo ssl_info; - CHECK(GetSSLInfo(&ssl_info)); + if (!GetSSLInfo(&ssl_info)) + return true; // This is not a secure session, so all domains are okay. - // HTTP/2 requires TLS 1.2+ - if (SSLConnectionStatusToVersion(ssl_info.connection_status) < - SSL_CONNECTION_VERSION_TLS1_2) { - return false; - } - - if (!IsTLSCipherSuiteAllowedByHTTP2( - SSLConnectionStatusToCipherSuite(ssl_info.connection_status))) { - return false; - } - - return true; -} - -base::WeakPtr<SpdySession> SpdySession::GetWeakPtr() { - return weak_factory_.GetWeakPtr(); -} - -bool SpdySession::CloseOneIdleConnection() { - CHECK(!in_io_loop_); - DCHECK(pool_); - if (active_streams_.empty()) { - DoDrainSession(ERR_CONNECTION_CLOSED, "Closing idle connection."); - } - // Return false as the socket wasn't immediately closed. - return false; -} - -void SpdySession::DumpMemoryStats(StreamSocket::SocketMemoryStats* stats, - bool* is_session_active) const { - *is_session_active = is_active(); - connection_->DumpMemoryStats(stats); + return CanPool(transport_security_state_, ssl_info, host_port_pair().host(), + domain); } void SpdySession::EnqueueStreamWrite( @@ -1244,10 +1065,9 @@ // just a FIN with no payload. if (effective_len != 0) { DecreaseSendWindowSize(static_cast<int32_t>(effective_len)); - data_buffer->AddConsumeCallback( - base::Bind(&SpdySession::OnWriteBufferConsumed, - weak_factory_.GetWeakPtr(), - static_cast<size_t>(effective_len))); + data_buffer->AddConsumeCallback(base::Bind( + &SpdySession::OnWriteBufferConsumed, weak_factory_.GetWeakPtr(), + static_cast<size_t>(effective_len))); } return data_buffer; @@ -1265,8 +1085,8 @@ CloseActiveStreamIterator(it, status); } -void SpdySession::CloseCreatedStream( - const base::WeakPtr<SpdyStream>& stream, int status) { +void SpdySession::CloseCreatedStream(const base::WeakPtr<SpdyStream>& stream, + int status) { DCHECK_EQ(stream->stream_id(), 0u); CreatedStreamSet::iterator it = created_streams_.find(stream.get()); @@ -1302,6 +1122,557 @@ return LOAD_STATE_IDLE; } +url::SchemeHostPort SpdySession::GetServer() { + return url::SchemeHostPort(is_secure_ ? "https" : "http", + host_port_pair().host(), host_port_pair().port()); +} + +bool SpdySession::GetRemoteEndpoint(IPEndPoint* endpoint) { + return GetPeerAddress(endpoint) == OK; +} + +bool SpdySession::GetSSLInfo(SSLInfo* ssl_info) const { + return connection_->socket()->GetSSLInfo(ssl_info); +} + +Error SpdySession::GetTokenBindingSignature(crypto::ECPrivateKey* key, + TokenBindingType tb_type, + std::vector<uint8_t>* out) { + if (!is_secure_) { + NOTREACHED(); + return ERR_FAILED; + } + SSLClientSocket* ssl_socket = + static_cast<SSLClientSocket*>(connection_->socket()); + return ssl_socket->GetTokenBindingSignature(key, tb_type, out); +} + +bool SpdySession::WasAlpnNegotiated() const { + return connection_->socket()->WasAlpnNegotiated(); +} + +NextProto SpdySession::GetNegotiatedProtocol() const { + return connection_->socket()->GetNegotiatedProtocol(); +} + +void SpdySession::SendStreamWindowUpdate(SpdyStreamId stream_id, + uint32_t delta_window_size) { + ActiveStreamMap::const_iterator it = active_streams_.find(stream_id); + CHECK(it != active_streams_.end()); + CHECK_EQ(it->second->stream_id(), stream_id); + SendWindowUpdateFrame(stream_id, delta_window_size, it->second->priority()); +} + +void SpdySession::CloseSessionOnError(Error err, + const std::string& description) { + DCHECK_LT(err, ERR_IO_PENDING); + DoDrainSession(err, description); +} + +void SpdySession::MakeUnavailable() { + if (availability_state_ == STATE_AVAILABLE) { + availability_state_ = STATE_GOING_AWAY; + pool_->MakeSessionUnavailable(GetWeakPtr()); + } +} + +void SpdySession::StartGoingAway(SpdyStreamId last_good_stream_id, + Error status) { + DCHECK_GE(availability_state_, STATE_GOING_AWAY); + + // The loops below are carefully written to avoid reentrancy problems. + + while (true) { + size_t old_size = GetTotalSize(pending_create_stream_queues_); + base::WeakPtr<SpdyStreamRequest> pending_request = + GetNextPendingStreamRequest(); + if (!pending_request) + break; + // No new stream requests should be added while the session is + // going away. + DCHECK_GT(old_size, GetTotalSize(pending_create_stream_queues_)); + pending_request->OnRequestCompleteFailure(ERR_ABORTED); + } + + while (true) { + size_t old_size = active_streams_.size(); + ActiveStreamMap::iterator it = + active_streams_.lower_bound(last_good_stream_id + 1); + if (it == active_streams_.end()) + break; + LogAbandonedActiveStream(it, status); + CloseActiveStreamIterator(it, status); + // No new streams should be activated while the session is going + // away. + DCHECK_GT(old_size, active_streams_.size()); + } + + while (!created_streams_.empty()) { + size_t old_size = created_streams_.size(); + CreatedStreamSet::iterator it = created_streams_.begin(); + LogAbandonedStream(*it, status); + CloseCreatedStreamIterator(it, status); + // No new streams should be created while the session is going + // away. + DCHECK_GT(old_size, created_streams_.size()); + } + + write_queue_.RemovePendingWritesForStreamsAfter(last_good_stream_id); + + DcheckGoingAway(); + MaybeFinishGoingAway(); +} + +void SpdySession::MaybeFinishGoingAway() { + if (active_streams_.empty() && created_streams_.empty() && + availability_state_ == STATE_GOING_AWAY) { + DoDrainSession(OK, "Finished going away"); + } +} + +std::unique_ptr<base::Value> SpdySession::GetInfoAsValue() const { + std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); + + dict->SetInteger("source_id", net_log_.source().id); + + dict->SetString("host_port_pair", host_port_pair().ToString()); + if (!pooled_aliases_.empty()) { + std::unique_ptr<base::ListValue> alias_list(new base::ListValue()); + for (const auto& alias : pooled_aliases_) { + alias_list->AppendString(alias.host_port_pair().ToString()); + } + dict->Set("aliases", std::move(alias_list)); + } + dict->SetString("proxy", host_port_proxy_pair().second.ToURI()); + + dict->SetInteger("active_streams", active_streams_.size()); + + dict->SetInteger("unclaimed_pushed_streams", + unclaimed_pushed_streams_.size()); + + dict->SetBoolean("is_secure", is_secure_); + + dict->SetString( + "negotiated_protocol", + NextProtoToString(connection_->socket()->GetNegotiatedProtocol())); + + dict->SetInteger("error", error_on_close_); + dict->SetInteger("max_concurrent_streams", max_concurrent_streams_); + + dict->SetInteger("streams_initiated_count", streams_initiated_count_); + dict->SetInteger("streams_pushed_count", streams_pushed_count_); + dict->SetInteger("streams_pushed_and_claimed_count", + streams_pushed_and_claimed_count_); + dict->SetInteger("streams_abandoned_count", streams_abandoned_count_); + DCHECK(buffered_spdy_framer_.get()); + dict->SetInteger("frames_received", buffered_spdy_framer_->frames_received()); + + dict->SetInteger("send_window_size", session_send_window_size_); + dict->SetInteger("recv_window_size", session_recv_window_size_); + dict->SetInteger("unacked_recv_window_bytes", + session_unacked_recv_window_bytes_); + return std::move(dict); +} + +bool SpdySession::IsReused() const { + return buffered_spdy_framer_->frames_received() > 0 || + connection_->reuse_type() == ClientSocketHandle::UNUSED_IDLE; +} + +bool SpdySession::GetLoadTimingInfo(SpdyStreamId stream_id, + LoadTimingInfo* load_timing_info) const { + return connection_->GetLoadTimingInfo(stream_id != kFirstStreamId, + load_timing_info); +} + +size_t SpdySession::num_unclaimed_pushed_streams() const { + return unclaimed_pushed_streams_.size(); +} + +size_t SpdySession::count_unclaimed_pushed_streams_for_url( + const GURL& url) const { + return unclaimed_pushed_streams_.count(url); +} + +int SpdySession::GetPeerAddress(IPEndPoint* address) const { + if (connection_->socket()) + return connection_->socket()->GetPeerAddress(address); + + return ERR_SOCKET_NOT_CONNECTED; +} + +int SpdySession::GetLocalAddress(IPEndPoint* address) const { + if (connection_->socket()) + return connection_->socket()->GetLocalAddress(address); + + return ERR_SOCKET_NOT_CONNECTED; +} + +void SpdySession::AddPooledAlias(const SpdySessionKey& alias_key) { + pooled_aliases_.insert(alias_key); +} + +bool SpdySession::HasAcceptableTransportSecurity() const { + // If we're not even using TLS, we have no standards to meet. + if (!is_secure_) { + return true; + } + + SSLInfo ssl_info; + CHECK(GetSSLInfo(&ssl_info)); + + // HTTP/2 requires TLS 1.2+ + if (SSLConnectionStatusToVersion(ssl_info.connection_status) < + SSL_CONNECTION_VERSION_TLS1_2) { + return false; + } + + if (!IsTLSCipherSuiteAllowedByHTTP2( + SSLConnectionStatusToCipherSuite(ssl_info.connection_status))) { + return false; + } + + return true; +} + +base::WeakPtr<SpdySession> SpdySession::GetWeakPtr() { + return weak_factory_.GetWeakPtr(); +} + +bool SpdySession::CloseOneIdleConnection() { + CHECK(!in_io_loop_); + DCHECK(pool_); + if (active_streams_.empty()) { + DoDrainSession(ERR_CONNECTION_CLOSED, "Closing idle connection."); + } + // Return false as the socket wasn't immediately closed. + return false; +} + +void SpdySession::DumpMemoryStats(StreamSocket::SocketMemoryStats* stats, + bool* is_session_active) const { + *is_session_active = is_active(); + connection_->DumpMemoryStats(stats); +} + +// {,Try}CreateStream() can be called with |in_io_loop_| set if a stream is +// being created in response to another being closed due to received data. + +int SpdySession::TryCreateStream( + const base::WeakPtr<SpdyStreamRequest>& request, + base::WeakPtr<SpdyStream>* stream) { + DCHECK(request); + + if (availability_state_ == STATE_GOING_AWAY) + return ERR_FAILED; + + if (availability_state_ == STATE_DRAINING) + return ERR_CONNECTION_CLOSED; + + if ((active_streams_.size() + created_streams_.size() - num_pushed_streams_ < + max_concurrent_streams_)) { + return CreateStream(*request, stream); + } + + if (net_log().IsCapturing()) { + net_log().AddEvent( + NetLogEventType::HTTP2_SESSION_STALLED_MAX_STREAMS, + base::Bind(&NetLogSpdySessionStalledCallback, active_streams_.size(), + created_streams_.size(), num_pushed_streams_, + max_concurrent_streams_, request->url().spec())); + } + RequestPriority priority = request->priority(); + CHECK_GE(priority, MINIMUM_PRIORITY); + CHECK_LE(priority, MAXIMUM_PRIORITY); + pending_create_stream_queues_[priority].push_back(request); + return ERR_IO_PENDING; +} + +int SpdySession::CreateStream(const SpdyStreamRequest& request, + base::WeakPtr<SpdyStream>* stream) { + DCHECK_GE(request.priority(), MINIMUM_PRIORITY); + DCHECK_LE(request.priority(), MAXIMUM_PRIORITY); + + if (availability_state_ == STATE_GOING_AWAY) + return ERR_FAILED; + + if (availability_state_ == STATE_DRAINING) + return ERR_CONNECTION_CLOSED; + + DCHECK(connection_->socket()); + UMA_HISTOGRAM_BOOLEAN("Net.SpdySession.CreateStreamWithSocketConnected", + connection_->socket()->IsConnected()); + if (!connection_->socket()->IsConnected()) { + DoDrainSession( + ERR_CONNECTION_CLOSED, + "Tried to create SPDY stream for a closed socket connection."); + return ERR_CONNECTION_CLOSED; + } + + std::unique_ptr<SpdyStream> new_stream( + new SpdyStream(request.type(), GetWeakPtr(), request.url(), + request.priority(), stream_initial_send_window_size_, + stream_max_recv_window_size_, request.net_log())); + *stream = new_stream->GetWeakPtr(); + InsertCreatedStream(std::move(new_stream)); + + return OK; +} + +void SpdySession::CancelStreamRequest( + const base::WeakPtr<SpdyStreamRequest>& request) { + DCHECK(request); + RequestPriority priority = request->priority(); + CHECK_GE(priority, MINIMUM_PRIORITY); + CHECK_LE(priority, MAXIMUM_PRIORITY); + +#if DCHECK_IS_ON() + // |request| should not be in a queue not matching its priority. + for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) { + if (priority == i) + continue; + PendingStreamRequestQueue* queue = &pending_create_stream_queues_[i]; + DCHECK(std::find_if(queue->begin(), queue->end(), RequestEquals(request)) == + queue->end()); + } +#endif + + PendingStreamRequestQueue* queue = &pending_create_stream_queues_[priority]; + // Remove |request| from |queue| while preserving the order of the + // other elements. + PendingStreamRequestQueue::iterator it = + std::find_if(queue->begin(), queue->end(), RequestEquals(request)); + // The request may already be removed if there's a + // CompleteStreamRequest() in flight. + if (it != queue->end()) { + it = queue->erase(it); + // |request| should be in the queue at most once, and if it is + // present, should not be pending completion. + DCHECK(std::find_if(it, queue->end(), RequestEquals(request)) == + queue->end()); + } +} + +base::WeakPtr<SpdyStreamRequest> SpdySession::GetNextPendingStreamRequest() { + for (int j = MAXIMUM_PRIORITY; j >= MINIMUM_PRIORITY; --j) { + if (pending_create_stream_queues_[j].empty()) + continue; + + base::WeakPtr<SpdyStreamRequest> pending_request = + pending_create_stream_queues_[j].front(); + DCHECK(pending_request); + pending_create_stream_queues_[j].pop_front(); + return pending_request; + } + return base::WeakPtr<SpdyStreamRequest>(); +} + +void SpdySession::ProcessPendingStreamRequests() { + size_t max_requests_to_process = + max_concurrent_streams_ - + (active_streams_.size() + created_streams_.size()); + for (size_t i = 0; i < max_requests_to_process; ++i) { + base::WeakPtr<SpdyStreamRequest> pending_request = + GetNextPendingStreamRequest(); + if (!pending_request) + break; + + // Note that this post can race with other stream creations, and it's + // possible that the un-stalled stream will be stalled again if it loses. + // TODO(jgraettinger): Provide stronger ordering guarantees. + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&SpdySession::CompleteStreamRequest, + weak_factory_.GetWeakPtr(), pending_request)); + } +} + +void SpdySession::TryCreatePushStream(SpdyStreamId stream_id, + SpdyStreamId associated_stream_id, + SpdyHeaderBlock headers) { + // Server-initiated streams should have even sequence numbers. + if ((stream_id & 0x1) != 0) { + LOG(WARNING) << "Received invalid push stream id " << stream_id; + CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR, "Odd push stream id."); + return; + } + + // Server-initiated streams must be associated with client-initiated streams. + if ((associated_stream_id & 0x1) != 1) { + LOG(WARNING) << "Received push stream id " << stream_id + << " with invalid associated stream id"; + CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR, "Push on even stream id."); + return; + } + + if (stream_id <= last_accepted_push_stream_id_) { + LOG(WARNING) << "Received push stream id " << stream_id + << " lesser or equal to the last accepted before"; + CloseSessionOnError( + ERR_SPDY_PROTOCOL_ERROR, + "New push stream id must be greater than the last accepted."); + return; + } + + if (IsStreamActive(stream_id)) { + // We should not get here, we'll start going away earlier on + // |last_seen_push_stream_id_| check. + LOG(WARNING) << "Received push for active stream " << stream_id; + return; + } + + last_accepted_push_stream_id_ = stream_id; + + // Pushed streams are speculative, so they start at an IDLE priority. + const RequestPriority request_priority = IDLE; + + if (availability_state_ == STATE_GOING_AWAY) { + // TODO(akalin): This behavior isn't in the SPDY spec, although it + // probably should be. + EnqueueResetStreamFrame(stream_id, request_priority, + ERROR_CODE_REFUSED_STREAM, + "push stream request received when going away"); + return; + } + + if (associated_stream_id == 0) { + // In HTTP/2 0 stream id in PUSH_PROMISE frame leads to framer error and + // session going away. We should never get here. + std::string description = base::StringPrintf( + "Received invalid associated stream id %d for pushed stream %d", + associated_stream_id, stream_id); + EnqueueResetStreamFrame(stream_id, request_priority, + ERROR_CODE_REFUSED_STREAM, description); + return; + } + + streams_pushed_count_++; + + // TODO(mbelshe): DCHECK that this is a GET method? + + // Verify that the response had a URL for us. + GURL gurl = GetUrlFromHeaderBlock(headers); + if (!gurl.is_valid()) { + EnqueueResetStreamFrame( + stream_id, request_priority, ERROR_CODE_PROTOCOL_ERROR, + "Pushed stream url was invalid: " + gurl.possibly_invalid_spec()); + return; + } + + // Verify we have a valid stream association. + ActiveStreamMap::iterator associated_it = + active_streams_.find(associated_stream_id); + if (associated_it == active_streams_.end()) { + EnqueueResetStreamFrame( + stream_id, request_priority, ERROR_CODE_STREAM_CLOSED, + base::StringPrintf("Received push for inactive associated stream %d", + associated_stream_id)); + return; + } + + DCHECK(gurl.is_valid()); + + // Check that the pushed stream advertises the same origin as its associated + // stream. Bypass this check if and only if this session is with a SPDY proxy + // that is trusted explicitly as determined by the |proxy_delegate_| or if the + // proxy is pushing same-origin resources. + if (!HostPortPair::FromURL(gurl).Equals(host_port_pair())) { + if (proxy_delegate_ && + proxy_delegate_->IsTrustedSpdyProxy( + ProxyServer(ProxyServer::SCHEME_HTTPS, host_port_pair()))) { + // Disallow pushing of HTTPS content. + if (gurl.SchemeIs("https")) { + EnqueueResetStreamFrame( + stream_id, request_priority, ERROR_CODE_REFUSED_STREAM, + base::StringPrintf("Rejected push of cross origin HTTPS content %d " + "from trusted proxy", + associated_stream_id)); + return; + } + } else { + GURL associated_url(associated_it->second->GetUrlFromHeaders()); + if (associated_url.SchemeIs("https")) { + SSLInfo ssl_info; + CHECK(GetSSLInfo(&ssl_info)); + if (!gurl.SchemeIs("https") || + !CanPool(transport_security_state_, ssl_info, associated_url.host(), + gurl.host())) { + EnqueueResetStreamFrame( + stream_id, request_priority, ERROR_CODE_REFUSED_STREAM, + base::StringPrintf("Rejected push stream %d on secure connection", + associated_stream_id)); + return; + } + } else { + // TODO(bnc): Change SpdyNetworkTransactionTests to use secure sockets. + if (associated_url.GetOrigin() != gurl.GetOrigin()) { + EnqueueResetStreamFrame( + stream_id, request_priority, ERROR_CODE_REFUSED_STREAM, + base::StringPrintf( + "Rejected cross origin push stream %d on insecure connection", + associated_stream_id)); + return; + } + } + } + } + + // There should not be an existing pushed stream with the same path. + UnclaimedPushedStreamContainer::const_iterator pushed_it = + unclaimed_pushed_streams_.lower_bound(gurl); + if (pushed_it != unclaimed_pushed_streams_.end() && + pushed_it->first == gurl) { + EnqueueResetStreamFrame( + stream_id, request_priority, ERROR_CODE_PROTOCOL_ERROR, + "Received duplicate pushed stream with url: " + gurl.spec()); + return; + } + + std::unique_ptr<SpdyStream> stream( + new SpdyStream(SPDY_PUSH_STREAM, GetWeakPtr(), gurl, request_priority, + stream_initial_send_window_size_, + stream_max_recv_window_size_, net_log_)); + stream->set_stream_id(stream_id); + + // Convert RequestPriority to a SpdyPriority to send in a PRIORITY frame. + SpdyPriority spdy_priority = + ConvertRequestPriorityToSpdyPriority(request_priority); + SpdyStreamId dependency_id = 0; + bool exclusive = false; + priority_dependency_state_.OnStreamCreation(stream_id, spdy_priority, + &dependency_id, &exclusive); + EnqueuePriorityFrame(stream_id, dependency_id, + Spdy3PriorityToHttp2Weight(spdy_priority), exclusive); + + // PUSH_PROMISE arrives on associated stream. + associated_it->second->AddRawReceivedBytes(last_compressed_frame_len_); + last_compressed_frame_len_ = 0; + + UnclaimedPushedStreamContainer::const_iterator inserted_pushed_it = + unclaimed_pushed_streams_.insert(pushed_it, gurl, stream_id, + time_func_()); + DCHECK(inserted_pushed_it != pushed_it); + DeleteExpiredPushedStreams(); + + InsertActivatedStream(std::move(stream)); + + ActiveStreamMap::iterator active_it = active_streams_.find(stream_id); + if (active_it == active_streams_.end()) { + NOTREACHED(); + return; + } + + // Notify the push_delegate that a push promise has been received. + if (push_delegate_) { + push_delegate_->OnPush(base::MakeUnique<SpdyServerPushHelper>( + weak_factory_.GetWeakPtr(), gurl)); + } + + active_it->second->OnPushPromiseHeadersReceived(std::move(headers)); + DCHECK(active_it->second->IsReservedRemote()); + num_pushed_streams_++; + return; +} + void SpdySession::CloseActiveStreamIterator(ActiveStreamMap::iterator it, int status) { // TODO(mbelshe): We should send a RST_STREAM control frame here @@ -1465,10 +1836,9 @@ CHECK(connection_->socket()); read_state_ = READ_STATE_DO_READ_COMPLETE; return connection_->socket()->Read( - read_buffer_.get(), - kReadBufferSize, - base::Bind(&SpdySession::PumpReadLoop, - weak_factory_.GetWeakPtr(), READ_STATE_DO_READ_COMPLETE)); + read_buffer_.get(), kReadBufferSize, + base::Bind(&SpdySession::PumpReadLoop, weak_factory_.GetWeakPtr(), + READ_STATE_DO_READ_COMPLETE)); } int SpdySession::DoReadComplete(int result) { @@ -1526,6 +1896,17 @@ } } +void SpdySession::MaybePostWriteLoop() { + if (write_state_ == WRITE_STATE_IDLE) { + CHECK(!in_flight_write_); + write_state_ = WRITE_STATE_DO_WRITE; + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(&SpdySession::PumpWriteLoop, weak_factory_.GetWeakPtr(), + WRITE_STATE_DO_WRITE, OK)); + } +} + int SpdySession::DoWriteLoop(WriteState expected_write_state, int result) { CHECK(!in_io_loop_); DCHECK_NE(write_state_, WRITE_STATE_IDLE); @@ -1628,10 +2009,9 @@ scoped_refptr<IOBuffer> write_io_buffer = in_flight_write_->GetIOBufferForRemainingData(); return connection_->socket()->Write( - write_io_buffer.get(), - in_flight_write_->GetRemainingSize(), - base::Bind(&SpdySession::PumpWriteLoop, - weak_factory_.GetWeakPtr(), WRITE_STATE_DO_WRITE_COMPLETE)); + write_io_buffer.get(), in_flight_write_->GetRemainingSize(), + base::Bind(&SpdySession::PumpWriteLoop, weak_factory_.GetWeakPtr(), + WRITE_STATE_DO_WRITE_COMPLETE)); } int SpdySession::DoWriteComplete(int result) { @@ -1654,8 +2034,7 @@ // It should not be possible to have written more bytes than our // in_flight_write_. - DCHECK_LE(static_cast<size_t>(result), - in_flight_write_->GetRemainingSize()); + DCHECK_LE(static_cast<size_t>(result), in_flight_write_->GetRemainingSize()); if (result > 0) { in_flight_write_->Consume(static_cast<size_t>(result)); @@ -1669,8 +2048,7 @@ if (in_flight_write_stream_.get()) { DCHECK_GT(in_flight_write_frame_size_, 0u); in_flight_write_stream_->OnFrameWriteComplete( - in_flight_write_frame_type_, - in_flight_write_frame_size_); + in_flight_write_frame_type_, in_flight_write_frame_size_); } // Cleanup the write which just completed. @@ -1685,1065 +2063,6 @@ return OK; } -void SpdySession::DcheckGoingAway() const { -#if DCHECK_IS_ON() - DCHECK_GE(availability_state_, STATE_GOING_AWAY); - for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) { - DCHECK(pending_create_stream_queues_[i].empty()); - } - DCHECK(created_streams_.empty()); -#endif -} - -void SpdySession::DcheckDraining() const { - DcheckGoingAway(); - DCHECK_EQ(availability_state_, STATE_DRAINING); - DCHECK(active_streams_.empty()); - DCHECK(unclaimed_pushed_streams_.empty()); -} - -void SpdySession::StartGoingAway(SpdyStreamId last_good_stream_id, - Error status) { - DCHECK_GE(availability_state_, STATE_GOING_AWAY); - - // The loops below are carefully written to avoid reentrancy problems. - - while (true) { - size_t old_size = GetTotalSize(pending_create_stream_queues_); - base::WeakPtr<SpdyStreamRequest> pending_request = - GetNextPendingStreamRequest(); - if (!pending_request) - break; - // No new stream requests should be added while the session is - // going away. - DCHECK_GT(old_size, GetTotalSize(pending_create_stream_queues_)); - pending_request->OnRequestCompleteFailure(ERR_ABORTED); - } - - while (true) { - size_t old_size = active_streams_.size(); - ActiveStreamMap::iterator it = - active_streams_.lower_bound(last_good_stream_id + 1); - if (it == active_streams_.end()) - break; - LogAbandonedActiveStream(it, status); - CloseActiveStreamIterator(it, status); - // No new streams should be activated while the session is going - // away. - DCHECK_GT(old_size, active_streams_.size()); - } - - while (!created_streams_.empty()) { - size_t old_size = created_streams_.size(); - CreatedStreamSet::iterator it = created_streams_.begin(); - LogAbandonedStream(*it, status); - CloseCreatedStreamIterator(it, status); - // No new streams should be created while the session is going - // away. - DCHECK_GT(old_size, created_streams_.size()); - } - - write_queue_.RemovePendingWritesForStreamsAfter(last_good_stream_id); - - DcheckGoingAway(); - MaybeFinishGoingAway(); -} - -void SpdySession::MaybeFinishGoingAway() { - if (active_streams_.empty() && created_streams_.empty() && - availability_state_ == STATE_GOING_AWAY) { - DoDrainSession(OK, "Finished going away"); - } -} - -void SpdySession::DoDrainSession(Error err, const std::string& description) { - if (availability_state_ == STATE_DRAINING) { - return; - } - MakeUnavailable(); - - // Mark host_port_pair requiring HTTP/1.1 for subsequent connections. - if (err == ERR_HTTP_1_1_REQUIRED) { - http_server_properties_->SetHTTP11Required(host_port_pair()); - } - - // If |err| indicates an error occurred, inform the peer that we're closing - // and why. Don't GOAWAY on a graceful or idle close, as that may - // unnecessarily wake the radio. We could technically GOAWAY on network errors - // (we'll probably fail to actually write it, but that's okay), however many - // unit-tests would need to be updated. - if (err != OK && - err != ERR_ABORTED && // Used by SpdySessionPool to close idle sessions. - err != ERR_NETWORK_CHANGED && // Used to deprecate sessions on IP change. - err != ERR_SOCKET_NOT_CONNECTED && err != ERR_HTTP_1_1_REQUIRED && - err != ERR_CONNECTION_CLOSED && err != ERR_CONNECTION_RESET) { - // Enqueue a GOAWAY to inform the peer of why we're closing the connection. - SpdyGoAwayIR goaway_ir(last_accepted_push_stream_id_, - MapNetErrorToGoAwayStatus(err), - description); - EnqueueSessionWrite( - HIGHEST, GOAWAY, - std::unique_ptr<SpdySerializedFrame>(new SpdySerializedFrame( - buffered_spdy_framer_->SerializeFrame(goaway_ir)))); - } - - availability_state_ = STATE_DRAINING; - error_on_close_ = err; - - net_log_.AddEvent( - NetLogEventType::HTTP2_SESSION_CLOSE, - base::Bind(&NetLogSpdySessionCloseCallback, err, &description)); - - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SpdySession.ClosedOnError", -err); - - if (err == OK) { - // We ought to be going away already, as this is a graceful close. - DcheckGoingAway(); - } else { - StartGoingAway(0, err); - } - DcheckDraining(); - MaybePostWriteLoop(); -} - -void SpdySession::LogAbandonedStream(SpdyStream* stream, Error status) { - DCHECK(stream); - std::string description = base::StringPrintf( - "ABANDONED (stream_id=%d): ", stream->stream_id()) + - stream->url().spec(); - stream->LogStreamError(status, description); - // We don't increment the streams abandoned counter here. If the - // stream isn't active (i.e., it hasn't written anything to the wire - // yet) then it's as if it never existed. If it is active, then - // LogAbandonedActiveStream() will increment the counters. -} - -void SpdySession::LogAbandonedActiveStream(ActiveStreamMap::const_iterator it, - Error status) { - DCHECK_GT(it->first, 0u); - LogAbandonedStream(it->second, status); - ++streams_abandoned_count_; -} - -SpdyStreamId SpdySession::GetNewStreamId() { - CHECK_LE(stream_hi_water_mark_, kLastStreamId); - SpdyStreamId id = stream_hi_water_mark_; - stream_hi_water_mark_ += 2; - return id; -} - -void SpdySession::CloseSessionOnError(Error err, - const std::string& description) { - DCHECK_LT(err, ERR_IO_PENDING); - DoDrainSession(err, description); -} - -void SpdySession::MakeUnavailable() { - if (availability_state_ == STATE_AVAILABLE) { - availability_state_ = STATE_GOING_AWAY; - pool_->MakeSessionUnavailable(GetWeakPtr()); - } -} - -std::unique_ptr<base::Value> SpdySession::GetInfoAsValue() const { - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); - - dict->SetInteger("source_id", net_log_.source().id); - - dict->SetString("host_port_pair", host_port_pair().ToString()); - if (!pooled_aliases_.empty()) { - std::unique_ptr<base::ListValue> alias_list(new base::ListValue()); - for (const auto& alias : pooled_aliases_) { - alias_list->AppendString(alias.host_port_pair().ToString()); - } - dict->Set("aliases", std::move(alias_list)); - } - dict->SetString("proxy", host_port_proxy_pair().second.ToURI()); - - dict->SetInteger("active_streams", active_streams_.size()); - - dict->SetInteger("unclaimed_pushed_streams", - unclaimed_pushed_streams_.size()); - - dict->SetBoolean("is_secure", is_secure_); - - dict->SetString( - "negotiated_protocol", - NextProtoToString(connection_->socket()->GetNegotiatedProtocol())); - - dict->SetInteger("error", error_on_close_); - dict->SetInteger("max_concurrent_streams", max_concurrent_streams_); - - dict->SetInteger("streams_initiated_count", streams_initiated_count_); - dict->SetInteger("streams_pushed_count", streams_pushed_count_); - dict->SetInteger("streams_pushed_and_claimed_count", - streams_pushed_and_claimed_count_); - dict->SetInteger("streams_abandoned_count", streams_abandoned_count_); - DCHECK(buffered_spdy_framer_.get()); - dict->SetInteger("frames_received", buffered_spdy_framer_->frames_received()); - - dict->SetInteger("send_window_size", session_send_window_size_); - dict->SetInteger("recv_window_size", session_recv_window_size_); - dict->SetInteger("unacked_recv_window_bytes", - session_unacked_recv_window_bytes_); - return std::move(dict); -} - -bool SpdySession::IsReused() const { - return buffered_spdy_framer_->frames_received() > 0 || - connection_->reuse_type() == ClientSocketHandle::UNUSED_IDLE; -} - -bool SpdySession::GetLoadTimingInfo(SpdyStreamId stream_id, - LoadTimingInfo* load_timing_info) const { - return connection_->GetLoadTimingInfo(stream_id != kFirstStreamId, - load_timing_info); -} - -size_t SpdySession::num_unclaimed_pushed_streams() const { - return unclaimed_pushed_streams_.size(); -} - -size_t SpdySession::count_unclaimed_pushed_streams_for_url( - const GURL& url) const { - return unclaimed_pushed_streams_.count(url); -} - -int SpdySession::GetPeerAddress(IPEndPoint* address) const { - if (connection_->socket()) - return connection_->socket()->GetPeerAddress(address); - - return ERR_SOCKET_NOT_CONNECTED; -} - -int SpdySession::GetLocalAddress(IPEndPoint* address) const { - if (connection_->socket()) - return connection_->socket()->GetLocalAddress(address); - - return ERR_SOCKET_NOT_CONNECTED; -} - -void SpdySession::EnqueueSessionWrite( - RequestPriority priority, - SpdyFrameType frame_type, - std::unique_ptr<SpdySerializedFrame> frame) { - DCHECK(frame_type == RST_STREAM || frame_type == SETTINGS || - frame_type == WINDOW_UPDATE || frame_type == PING || - frame_type == GOAWAY); - EnqueueWrite( - priority, frame_type, - std::unique_ptr<SpdyBufferProducer>(new SimpleBufferProducer( - std::unique_ptr<SpdyBuffer>(new SpdyBuffer(std::move(frame))))), - base::WeakPtr<SpdyStream>()); -} - -void SpdySession::EnqueueWrite(RequestPriority priority, - SpdyFrameType frame_type, - std::unique_ptr<SpdyBufferProducer> producer, - const base::WeakPtr<SpdyStream>& stream) { - if (availability_state_ == STATE_DRAINING) - return; - - write_queue_.Enqueue(priority, frame_type, std::move(producer), stream); - MaybePostWriteLoop(); -} - -void SpdySession::MaybePostWriteLoop() { - if (write_state_ == WRITE_STATE_IDLE) { - CHECK(!in_flight_write_); - write_state_ = WRITE_STATE_DO_WRITE; - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&SpdySession::PumpWriteLoop, weak_factory_.GetWeakPtr(), - WRITE_STATE_DO_WRITE, OK)); - } -} - -void SpdySession::InsertCreatedStream(std::unique_ptr<SpdyStream> stream) { - CHECK_EQ(stream->stream_id(), 0u); - CHECK(created_streams_.find(stream.get()) == created_streams_.end()); - created_streams_.insert(stream.release()); -} - -std::unique_ptr<SpdyStream> SpdySession::ActivateCreatedStream( - SpdyStream* stream) { - CHECK_EQ(stream->stream_id(), 0u); - CHECK(created_streams_.find(stream) != created_streams_.end()); - stream->set_stream_id(GetNewStreamId()); - std::unique_ptr<SpdyStream> owned_stream(stream); - created_streams_.erase(stream); - return owned_stream; -} - -void SpdySession::InsertActivatedStream(std::unique_ptr<SpdyStream> stream) { - SpdyStreamId stream_id = stream->stream_id(); - CHECK_NE(stream_id, 0u); - std::pair<ActiveStreamMap::iterator, bool> result = - active_streams_.insert(std::make_pair(stream_id, stream.get())); - CHECK(result.second); - ignore_result(stream.release()); -} - -void SpdySession::DeleteStream(std::unique_ptr<SpdyStream> stream, int status) { - if (in_flight_write_stream_.get() == stream.get()) { - // If we're deleting the stream for the in-flight write, we still - // need to let the write complete, so we clear - // |in_flight_write_stream_| and let the write finish on its own - // without notifying |in_flight_write_stream_|. - in_flight_write_stream_.reset(); - } - - write_queue_.RemovePendingWritesForStream(stream->GetWeakPtr()); - stream->OnClose(status); - - if (availability_state_ == STATE_AVAILABLE) { - ProcessPendingStreamRequests(); - } -} - -SpdyStreamId SpdySession::GetStreamIdForPush(const GURL& url) { - UnclaimedPushedStreamContainer::const_iterator unclaimed_it = - unclaimed_pushed_streams_.find(url); - if (unclaimed_it == unclaimed_pushed_streams_.end()) - return 0; - return unclaimed_it->second.stream_id; -} - -SpdyStream* SpdySession::GetActivePushStream(const GURL& url) { - UnclaimedPushedStreamContainer::const_iterator unclaimed_it = - unclaimed_pushed_streams_.find(url); - if (unclaimed_it == unclaimed_pushed_streams_.end()) - return nullptr; - - SpdyStreamId stream_id = unclaimed_it->second.stream_id; - unclaimed_pushed_streams_.erase(unclaimed_it); - - ActiveStreamMap::iterator active_it = active_streams_.find(stream_id); - if (active_it == active_streams_.end()) { - NOTREACHED(); - return nullptr; - } - - net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_ADOPTED_PUSH_STREAM, - base::Bind(&NetLogSpdyAdoptedPushStreamCallback, - active_it->second->stream_id(), &url)); - return active_it->second; -} - -url::SchemeHostPort SpdySession::GetServer() { - return url::SchemeHostPort(is_secure_ ? "https" : "http", - host_port_pair().host(), host_port_pair().port()); -} - -bool SpdySession::GetRemoteEndpoint(IPEndPoint* endpoint) { - return GetPeerAddress(endpoint) == OK; -} - -bool SpdySession::GetSSLInfo(SSLInfo* ssl_info) const { - return connection_->socket()->GetSSLInfo(ssl_info); -} - -bool SpdySession::WasAlpnNegotiated() const { - return connection_->socket()->WasAlpnNegotiated(); -} - -NextProto SpdySession::GetNegotiatedProtocol() const { - return connection_->socket()->GetNegotiatedProtocol(); -} - -Error SpdySession::GetTokenBindingSignature(crypto::ECPrivateKey* key, - TokenBindingType tb_type, - std::vector<uint8_t>* out) { - if (!is_secure_) { - NOTREACHED(); - return ERR_FAILED; - } - SSLClientSocket* ssl_socket = - static_cast<SSLClientSocket*>(connection_->socket()); - return ssl_socket->GetTokenBindingSignature(key, tb_type, out); -} - -void SpdySession::OnError(SpdyFramer::SpdyFramerError spdy_framer_error) { - CHECK(in_io_loop_); - - RecordProtocolErrorHistogram( - MapFramerErrorToProtocolError(spdy_framer_error)); - std::string description = base::StringPrintf( - "Framer error: %d (%s).", spdy_framer_error, - SpdyFramer::SpdyFramerErrorToString(spdy_framer_error)); - DoDrainSession(MapFramerErrorToNetError(spdy_framer_error), description); -} - -void SpdySession::OnStreamError(SpdyStreamId stream_id, - const std::string& description) { - CHECK(in_io_loop_); - - ActiveStreamMap::iterator it = active_streams_.find(stream_id); - if (it == active_streams_.end()) { - // We still want to send a frame to reset the stream even if we - // don't know anything about it. - EnqueueResetStreamFrame(stream_id, IDLE, ERROR_CODE_PROTOCOL_ERROR, - description); - return; - } - - ResetStreamIterator(it, ERROR_CODE_PROTOCOL_ERROR, description); -} - -void SpdySession::OnDataFrameHeader(SpdyStreamId stream_id, - size_t length, - bool fin) { - CHECK(in_io_loop_); - - ActiveStreamMap::iterator it = active_streams_.find(stream_id); - - // By the time data comes in, the stream may already be inactive. - if (it == active_streams_.end()) - return; - - SpdyStream* stream = it->second; - CHECK_EQ(stream->stream_id(), stream_id); - - DCHECK(buffered_spdy_framer_); - size_t header_len = buffered_spdy_framer_->GetDataFrameMinimumSize(); - stream->AddRawReceivedBytes(header_len); -} - -void SpdySession::OnStreamFrameData(SpdyStreamId stream_id, - const char* data, - size_t len) { - CHECK(in_io_loop_); - DCHECK_LT(len, 1u << 24); - if (net_log().IsCapturing()) { - net_log().AddEvent( - NetLogEventType::HTTP2_SESSION_RECV_DATA, - base::Bind(&NetLogSpdyDataCallback, stream_id, len, false)); - } - - // Build the buffer as early as possible so that we go through the - // session flow control checks and update - // |unacked_recv_window_bytes_| properly even when the stream is - // inactive (since the other side has still reduced its session send - // window). - std::unique_ptr<SpdyBuffer> buffer; - if (data) { - DCHECK_GT(len, 0u); - CHECK_LE(len, static_cast<size_t>(kReadBufferSize)); - buffer.reset(new SpdyBuffer(data, len)); - - DecreaseRecvWindowSize(static_cast<int32_t>(len)); - buffer->AddConsumeCallback(base::Bind(&SpdySession::OnReadBufferConsumed, - weak_factory_.GetWeakPtr())); - } else { - DCHECK_EQ(len, 0u); - } - - ActiveStreamMap::iterator it = active_streams_.find(stream_id); - - // By the time data comes in, the stream may already be inactive. - if (it == active_streams_.end()) - return; - - SpdyStream* stream = it->second; - CHECK_EQ(stream->stream_id(), stream_id); - - stream->AddRawReceivedBytes(len); - stream->OnDataReceived(std::move(buffer)); -} - -void SpdySession::OnStreamEnd(SpdyStreamId stream_id) { - CHECK(in_io_loop_); - if (net_log().IsCapturing()) { - net_log().AddEvent(NetLogEventType::HTTP2_SESSION_RECV_DATA, - base::Bind(&NetLogSpdyDataCallback, stream_id, 0, true)); - } - - ActiveStreamMap::iterator it = active_streams_.find(stream_id); - // By the time data comes in, the stream may already be inactive. - if (it == active_streams_.end()) - return; - - SpdyStream* stream = it->second; - CHECK_EQ(stream->stream_id(), stream_id); - - stream->OnDataReceived(std::unique_ptr<SpdyBuffer>()); -} - -void SpdySession::OnStreamPadding(SpdyStreamId stream_id, size_t len) { - CHECK(in_io_loop_); - - // Decrease window size because padding bytes are received. - // Increase window size because padding bytes are consumed (by discarding). - // Net result: |session_unacked_recv_window_bytes_| increases by |len|, - // |session_recv_window_size_| does not change. - DecreaseRecvWindowSize(static_cast<int32_t>(len)); - IncreaseRecvWindowSize(static_cast<int32_t>(len)); - - ActiveStreamMap::iterator it = active_streams_.find(stream_id); - if (it == active_streams_.end()) - return; - it->second->OnPaddingConsumed(len); -} - -void SpdySession::OnSettings() { - CHECK(in_io_loop_); - - if (net_log_.IsCapturing()) { - net_log_.AddEvent( - NetLogEventType::HTTP2_SESSION_RECV_SETTINGS, - base::Bind(&NetLogSpdyRecvSettingsCallback, host_port_pair())); - } - - // Send an acknowledgment of the setting. - SpdySettingsIR settings_ir; - settings_ir.set_is_ack(true); - EnqueueSessionWrite( - HIGHEST, SETTINGS, - std::unique_ptr<SpdySerializedFrame>(new SpdySerializedFrame( - buffered_spdy_framer_->SerializeFrame(settings_ir)))); -} - -void SpdySession::OnSetting(SpdySettingsIds id, uint32_t value) { - CHECK(in_io_loop_); - - HandleSetting(id, value); - - // Log the setting. - net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_SETTING, - base::Bind(&NetLogSpdyRecvSettingCallback, id, value)); -} - -void SpdySession::OnSendCompressedFrame( - SpdyStreamId stream_id, - SpdyFrameType type, - size_t payload_len, - size_t frame_len) { - if (type != HEADERS) { - return; - } - - DCHECK(buffered_spdy_framer_.get()); - size_t compressed_len = - frame_len - buffered_spdy_framer_->GetFrameMinimumSize(); - - if (payload_len) { - // Make sure we avoid early decimal truncation. - int compression_pct = 100 - (100 * compressed_len) / payload_len; - UMA_HISTOGRAM_PERCENTAGE("Net.SpdyHeadersCompressionPercentage", - compression_pct); - } -} - -void SpdySession::OnReceiveCompressedFrame( - SpdyStreamId stream_id, - SpdyFrameType type, - size_t frame_len) { - last_compressed_frame_len_ = frame_len; -} - -void SpdySession::DeleteExpiredPushedStreams() { - if (unclaimed_pushed_streams_.empty()) - return; - - // Check that adequate time has elapsed since the last sweep. - if (time_func_() < next_unclaimed_push_stream_sweep_time_) - return; - - // Gather old streams to delete. - base::TimeTicks minimum_freshness = time_func_() - - base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds); - std::vector<SpdyStreamId> streams_to_close; - for (UnclaimedPushedStreamContainer::const_iterator it = - unclaimed_pushed_streams_.begin(); - it != unclaimed_pushed_streams_.end(); ++it) { - if (minimum_freshness > it->second.creation_time) - streams_to_close.push_back(it->second.stream_id); - } - - for (std::vector<SpdyStreamId>::const_iterator to_close_it = - streams_to_close.begin(); - to_close_it != streams_to_close.end(); ++to_close_it) { - ActiveStreamMap::iterator active_it = active_streams_.find(*to_close_it); - if (active_it == active_streams_.end()) - continue; - bytes_pushed_and_unclaimed_count_ += active_it->second->recv_bytes(); - - LogAbandonedActiveStream(active_it, ERR_INVALID_SPDY_STREAM); - // CloseActiveStreamIterator() will remove the stream from - // |unclaimed_pushed_streams_|. - ResetStreamIterator(active_it, ERROR_CODE_REFUSED_STREAM, - "Stream not claimed."); - } - - next_unclaimed_push_stream_sweep_time_ = time_func_() + - base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds); -} - -void SpdySession::OnHeaders(SpdyStreamId stream_id, - bool has_priority, - int weight, - SpdyStreamId parent_stream_id, - bool exclusive, - bool fin, - SpdyHeaderBlock headers) { - CHECK(in_io_loop_); - - if (net_log().IsCapturing()) { - net_log().AddEvent(NetLogEventType::HTTP2_SESSION_RECV_HEADERS, - base::Bind(&NetLogSpdyHeadersReceivedCallback, &headers, - fin, stream_id)); - } - - ActiveStreamMap::iterator it = active_streams_.find(stream_id); - if (it == active_streams_.end()) { - // NOTE: it may just be that the stream was cancelled. - LOG(WARNING) << "Received HEADERS for invalid stream " << stream_id; - return; - } - - SpdyStream* stream = it->second; - CHECK_EQ(stream->stream_id(), stream_id); - - stream->AddRawReceivedBytes(last_compressed_frame_len_); - last_compressed_frame_len_ = 0; - - if (it->second->IsReservedRemote()) { - DCHECK_EQ(SPDY_PUSH_STREAM, stream->type()); - if (max_concurrent_pushed_streams_ && - num_active_pushed_streams_ >= max_concurrent_pushed_streams_) { - ResetStream(stream_id, ERROR_CODE_REFUSED_STREAM, - "Stream concurrency limit reached."); - return; - } - - // Will be balanced in DeleteStream. - num_active_pushed_streams_++; - } - - base::Time response_time = base::Time::Now(); - base::TimeTicks recv_first_byte_time = time_func_(); - // May invalidate |stream|. - stream->OnHeadersReceived(headers, response_time, recv_first_byte_time); -} - -void SpdySession::OnAltSvc( - SpdyStreamId stream_id, - base::StringPiece origin, - const SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector) { - if (!is_secure_) - return; - - url::SchemeHostPort scheme_host_port; - if (stream_id == 0) { - if (origin.empty()) - return; - const GURL gurl(origin); - if (!gurl.SchemeIs("https")) - return; - SSLInfo ssl_info; - if (!GetSSLInfo(&ssl_info)) - return; - if (!CanPool(transport_security_state_, ssl_info, host_port_pair().host(), - gurl.host())) { - return; - } - scheme_host_port = url::SchemeHostPort(gurl); - } else { - if (!origin.empty()) - return; - const ActiveStreamMap::iterator it = active_streams_.find(stream_id); - if (it == active_streams_.end()) - return; - const GURL& gurl(it->second->url()); - if (!gurl.SchemeIs("https")) - return; - scheme_host_port = url::SchemeHostPort(gurl); - } - - AlternativeServiceInfoVector alternative_service_info_vector; - alternative_service_info_vector.reserve(altsvc_vector.size()); - const base::Time now(base::Time::Now()); - for (const SpdyAltSvcWireFormat::AlternativeService& altsvc : altsvc_vector) { - const NextProto protocol = NextProtoFromString(altsvc.protocol_id); - if (protocol == kProtoUnknown) - continue; - const AlternativeService alternative_service(protocol, altsvc.host, - altsvc.port); - const base::Time expiration = - now + base::TimeDelta::FromSeconds(altsvc.max_age); - alternative_service_info_vector.push_back( - AlternativeServiceInfo(alternative_service, expiration)); - } - http_server_properties_->SetAlternativeServices( - scheme_host_port, alternative_service_info_vector); -} - -bool SpdySession::OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) { - // Validate stream id. - // Was the frame sent on a stream id that has not been used in this session? - if (stream_id % 2 == 1 && stream_id > stream_hi_water_mark_) - return false; - - if (stream_id % 2 == 0 && stream_id > last_accepted_push_stream_id_) - return false; - - return true; -} - -void SpdySession::OnRstStream(SpdyStreamId stream_id, - SpdyErrorCode error_code) { - CHECK(in_io_loop_); - - net_log().AddEvent( - NetLogEventType::HTTP2_SESSION_RECV_RST_STREAM, - base::Bind(&NetLogSpdyRecvRstStreamCallback, stream_id, error_code)); - - ActiveStreamMap::iterator it = active_streams_.find(stream_id); - if (it == active_streams_.end()) { - // NOTE: it may just be that the stream was cancelled. - LOG(WARNING) << "Received RST for invalid stream" << stream_id; - return; - } - - CHECK_EQ(it->second->stream_id(), stream_id); - - if (error_code == ERROR_CODE_NO_ERROR) { - CloseActiveStreamIterator(it, ERR_SPDY_RST_STREAM_NO_ERROR_RECEIVED); - } else if (error_code == ERROR_CODE_REFUSED_STREAM) { - CloseActiveStreamIterator(it, ERR_SPDY_SERVER_REFUSED_STREAM); - } else if (error_code == ERROR_CODE_HTTP_1_1_REQUIRED) { - // TODO(bnc): Record histogram with number of open streams capped at 50. - it->second->LogStreamError( - ERR_HTTP_1_1_REQUIRED, - base::StringPrintf( - "SPDY session closed because of stream with error_code: %u", - error_code)); - DoDrainSession(ERR_HTTP_1_1_REQUIRED, "HTTP_1_1_REQUIRED for stream."); - } else { - RecordProtocolErrorHistogram( - PROTOCOL_ERROR_RST_STREAM_FOR_NON_ACTIVE_STREAM); - it->second->LogStreamError( - ERR_SPDY_PROTOCOL_ERROR, - base::StringPrintf("SPDY stream closed with error_code: %u", - error_code)); - // TODO(mbelshe): Map from Spdy-protocol errors to something sensical. - // For now, it doesn't matter much - it is a protocol error. - CloseActiveStreamIterator(it, ERR_SPDY_PROTOCOL_ERROR); - } -} - -void SpdySession::OnGoAway(SpdyStreamId last_accepted_stream_id, - SpdyErrorCode error_code, - base::StringPiece debug_data) { - CHECK(in_io_loop_); - - // TODO(jgraettinger): UMA histogram on |error_code|. - - net_log_.AddEvent( - NetLogEventType::HTTP2_SESSION_RECV_GOAWAY, - base::Bind(&NetLogSpdyRecvGoAwayCallback, last_accepted_stream_id, - active_streams_.size(), unclaimed_pushed_streams_.size(), - error_code, debug_data)); - MakeUnavailable(); - if (error_code == ERROR_CODE_HTTP_1_1_REQUIRED) { - // TODO(bnc): Record histogram with number of open streams capped at 50. - DoDrainSession(ERR_HTTP_1_1_REQUIRED, "HTTP_1_1_REQUIRED for stream."); - } else { - StartGoingAway(last_accepted_stream_id, ERR_ABORTED); - } - // This is to handle the case when we already don't have any active - // streams (i.e., StartGoingAway() did nothing). Otherwise, we have - // active streams and so the last one being closed will finish the - // going away process (see DeleteStream()). - MaybeFinishGoingAway(); -} - -void SpdySession::OnPing(SpdyPingId unique_id, bool is_ack) { - CHECK(in_io_loop_); - - net_log_.AddEvent( - NetLogEventType::HTTP2_SESSION_PING, - base::Bind(&NetLogSpdyPingCallback, unique_id, is_ack, "received")); - - // Send response to a PING from server. - if (!is_ack) { - WritePingFrame(unique_id, true); - return; - } - - --pings_in_flight_; - if (pings_in_flight_ < 0) { - RecordProtocolErrorHistogram(PROTOCOL_ERROR_UNEXPECTED_PING); - DoDrainSession(ERR_SPDY_PROTOCOL_ERROR, "pings_in_flight_ is < 0."); - pings_in_flight_ = 0; - return; - } - - if (pings_in_flight_ > 0) - return; - - // We will record RTT in histogram when there are no more client sent - // pings_in_flight_. - RecordPingRTTHistogram(time_func_() - last_ping_sent_time_); -} - -void SpdySession::OnWindowUpdate(SpdyStreamId stream_id, - int delta_window_size) { - CHECK(in_io_loop_); - - net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_WINDOW_UPDATE, - base::Bind(&NetLogSpdyWindowUpdateFrameCallback, stream_id, - delta_window_size)); - - if (stream_id == kSessionFlowControlStreamId) { - // WINDOW_UPDATE for the session. - if (delta_window_size < 1) { - RecordProtocolErrorHistogram(PROTOCOL_ERROR_INVALID_WINDOW_UPDATE_SIZE); - DoDrainSession( - ERR_SPDY_PROTOCOL_ERROR, - "Received WINDOW_UPDATE with an invalid delta_window_size " + - base::IntToString(delta_window_size)); - return; - } - - IncreaseSendWindowSize(delta_window_size); - } else { - // WINDOW_UPDATE for a stream. - ActiveStreamMap::iterator it = active_streams_.find(stream_id); - - if (it == active_streams_.end()) { - // NOTE: it may just be that the stream was cancelled. - LOG(WARNING) << "Received WINDOW_UPDATE for invalid stream " << stream_id; - return; - } - - SpdyStream* stream = it->second; - CHECK_EQ(stream->stream_id(), stream_id); - - if (delta_window_size < 1) { - ResetStreamIterator( - it, ERROR_CODE_FLOW_CONTROL_ERROR, - base::StringPrintf("Received WINDOW_UPDATE with an invalid " - "delta_window_size %d", - delta_window_size)); - return; - } - - CHECK_EQ(it->second->stream_id(), stream_id); - it->second->IncreaseSendWindowSize(delta_window_size); - } -} - -void SpdySession::TryCreatePushStream(SpdyStreamId stream_id, - SpdyStreamId associated_stream_id, - SpdyHeaderBlock headers) { - // Server-initiated streams should have even sequence numbers. - if ((stream_id & 0x1) != 0) { - LOG(WARNING) << "Received invalid push stream id " << stream_id; - CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR, "Odd push stream id."); - return; - } - - // Server-initiated streams must be associated with client-initiated streams. - if ((associated_stream_id & 0x1) != 1) { - LOG(WARNING) << "Received push stream id " << stream_id - << " with invalid associated stream id"; - CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR, "Push on even stream id."); - return; - } - - if (stream_id <= last_accepted_push_stream_id_) { - LOG(WARNING) << "Received push stream id " << stream_id - << " lesser or equal to the last accepted before"; - CloseSessionOnError( - ERR_SPDY_PROTOCOL_ERROR, - "New push stream id must be greater than the last accepted."); - return; - } - - if (IsStreamActive(stream_id)) { - // We should not get here, we'll start going away earlier on - // |last_seen_push_stream_id_| check. - LOG(WARNING) << "Received push for active stream " << stream_id; - return; - } - - last_accepted_push_stream_id_ = stream_id; - - // Pushed streams are speculative, so they start at an IDLE priority. - const RequestPriority request_priority = IDLE; - - if (availability_state_ == STATE_GOING_AWAY) { - // TODO(akalin): This behavior isn't in the SPDY spec, although it - // probably should be. - EnqueueResetStreamFrame(stream_id, request_priority, - ERROR_CODE_REFUSED_STREAM, - "push stream request received when going away"); - return; - } - - if (associated_stream_id == 0) { - // In HTTP/2 0 stream id in PUSH_PROMISE frame leads to framer error and - // session going away. We should never get here. - std::string description = base::StringPrintf( - "Received invalid associated stream id %d for pushed stream %d", - associated_stream_id, - stream_id); - EnqueueResetStreamFrame(stream_id, request_priority, - ERROR_CODE_REFUSED_STREAM, description); - return; - } - - streams_pushed_count_++; - - // TODO(mbelshe): DCHECK that this is a GET method? - - // Verify that the response had a URL for us. - GURL gurl = GetUrlFromHeaderBlock(headers); - if (!gurl.is_valid()) { - EnqueueResetStreamFrame(stream_id, request_priority, - ERROR_CODE_PROTOCOL_ERROR, - "Pushed stream url was invalid: " + gurl.spec()); - return; - } - - // Verify we have a valid stream association. - ActiveStreamMap::iterator associated_it = - active_streams_.find(associated_stream_id); - if (associated_it == active_streams_.end()) { - EnqueueResetStreamFrame( - stream_id, request_priority, ERROR_CODE_STREAM_CLOSED, - base::StringPrintf("Received push for inactive associated stream %d", - associated_stream_id)); - return; - } - - DCHECK(gurl.is_valid()); - - // Check that the pushed stream advertises the same origin as its associated - // stream. Bypass this check if and only if this session is with a SPDY proxy - // that is trusted explicitly as determined by the |proxy_delegate_| or if the - // proxy is pushing same-origin resources. - if (!HostPortPair::FromURL(gurl).Equals(host_port_pair())) { - if (proxy_delegate_ && - proxy_delegate_->IsTrustedSpdyProxy( - ProxyServer(ProxyServer::SCHEME_HTTPS, host_port_pair()))) { - // Disallow pushing of HTTPS content. - if (gurl.SchemeIs("https")) { - EnqueueResetStreamFrame( - stream_id, request_priority, ERROR_CODE_REFUSED_STREAM, - base::StringPrintf("Rejected push of cross origin HTTPS content %d " - "from trusted proxy", - associated_stream_id)); - return; - } - } else { - GURL associated_url(associated_it->second->GetUrlFromHeaders()); - if (associated_url.SchemeIs("https")) { - SSLInfo ssl_info; - CHECK(GetSSLInfo(&ssl_info)); - if (!gurl.SchemeIs("https") || - !CanPool(transport_security_state_, ssl_info, associated_url.host(), - gurl.host())) { - EnqueueResetStreamFrame( - stream_id, request_priority, ERROR_CODE_REFUSED_STREAM, - base::StringPrintf("Rejected push stream %d on secure connection", - associated_stream_id)); - return; - } - } else { - // TODO(bnc): Change SpdyNetworkTransactionTests to use secure sockets. - if (associated_url.GetOrigin() != gurl.GetOrigin()) { - EnqueueResetStreamFrame( - stream_id, request_priority, ERROR_CODE_REFUSED_STREAM, - base::StringPrintf( - "Rejected cross origin push stream %d on insecure connection", - associated_stream_id)); - return; - } - } - } - } - - // There should not be an existing pushed stream with the same path. - UnclaimedPushedStreamContainer::const_iterator pushed_it = - unclaimed_pushed_streams_.lower_bound(gurl); - if (pushed_it != unclaimed_pushed_streams_.end() && - pushed_it->first == gurl) { - EnqueueResetStreamFrame( - stream_id, request_priority, ERROR_CODE_PROTOCOL_ERROR, - "Received duplicate pushed stream with url: " + gurl.spec()); - return; - } - - std::unique_ptr<SpdyStream> stream( - new SpdyStream(SPDY_PUSH_STREAM, GetWeakPtr(), gurl, request_priority, - stream_initial_send_window_size_, - stream_max_recv_window_size_, net_log_)); - stream->set_stream_id(stream_id); - - // Convert RequestPriority to a SpdyPriority to send in a PRIORITY frame. - SpdyPriority spdy_priority = - ConvertRequestPriorityToSpdyPriority(request_priority); - SpdyStreamId dependency_id = 0; - bool exclusive = false; - priority_dependency_state_.OnStreamCreation(stream_id, spdy_priority, - &dependency_id, &exclusive); - EnqueuePriorityFrame(stream_id, dependency_id, - Spdy3PriorityToHttp2Weight(spdy_priority), exclusive); - - // PUSH_PROMISE arrives on associated stream. - associated_it->second->AddRawReceivedBytes(last_compressed_frame_len_); - last_compressed_frame_len_ = 0; - - UnclaimedPushedStreamContainer::const_iterator inserted_pushed_it = - unclaimed_pushed_streams_.insert(pushed_it, gurl, stream_id, - time_func_()); - DCHECK(inserted_pushed_it != pushed_it); - DeleteExpiredPushedStreams(); - - InsertActivatedStream(std::move(stream)); - - ActiveStreamMap::iterator active_it = active_streams_.find(stream_id); - if (active_it == active_streams_.end()) { - NOTREACHED(); - return; - } - - // Notify the push_delegate that a push promise has been received. - if (push_delegate_) { - push_delegate_->OnPush(base::MakeUnique<SpdyServerPushHelper>( - weak_factory_.GetWeakPtr(), gurl)); - } - - active_it->second->OnPushPromiseHeadersReceived(std::move(headers)); - DCHECK(active_it->second->IsReservedRemote()); - num_pushed_streams_++; - return; -} - -void SpdySession::OnPushPromise(SpdyStreamId stream_id, - SpdyStreamId promised_stream_id, - SpdyHeaderBlock headers) { - CHECK(in_io_loop_); - - if (net_log_.IsCapturing()) { - net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_PUSH_PROMISE, - base::Bind(&NetLogSpdyPushPromiseReceivedCallback, - &headers, stream_id, promised_stream_id)); - } - - TryCreatePushStream(promised_stream_id, stream_id, std::move(headers)); -} - -void SpdySession::SendStreamWindowUpdate(SpdyStreamId stream_id, - uint32_t delta_window_size) { - ActiveStreamMap::const_iterator it = active_streams_.find(stream_id); - CHECK(it != active_streams_.end()); - CHECK_EQ(it->second->stream_id(), stream_id); - SendWindowUpdateFrame(stream_id, delta_window_size, it->second->priority()); -} - void SpdySession::SendInitialData() { DCHECK(enable_sending_initial_data_); @@ -2793,8 +2112,8 @@ void SpdySession::HandleSetting(uint32_t id, uint32_t value) { switch (id) { case SETTINGS_MAX_CONCURRENT_STREAMS: - max_concurrent_streams_ = std::min(static_cast<size_t>(value), - kMaxConcurrentStreamLimit); + max_concurrent_streams_ = + std::min(static_cast<size_t>(value), kMaxConcurrentStreamLimit); ProcessPendingStreamRequests(); break; case SETTINGS_INITIAL_WINDOW_SIZE: { @@ -2920,23 +2239,115 @@ delay); } +SpdyStreamId SpdySession::GetNewStreamId() { + CHECK_LE(stream_hi_water_mark_, kLastStreamId); + SpdyStreamId id = stream_hi_water_mark_; + stream_hi_water_mark_ += 2; + return id; +} + +void SpdySession::EnqueueSessionWrite( + RequestPriority priority, + SpdyFrameType frame_type, + std::unique_ptr<SpdySerializedFrame> frame) { + DCHECK(frame_type == RST_STREAM || frame_type == SETTINGS || + frame_type == WINDOW_UPDATE || frame_type == PING || + frame_type == GOAWAY); + EnqueueWrite( + priority, frame_type, + std::unique_ptr<SpdyBufferProducer>(new SimpleBufferProducer( + std::unique_ptr<SpdyBuffer>(new SpdyBuffer(std::move(frame))))), + base::WeakPtr<SpdyStream>()); +} + +void SpdySession::EnqueueWrite(RequestPriority priority, + SpdyFrameType frame_type, + std::unique_ptr<SpdyBufferProducer> producer, + const base::WeakPtr<SpdyStream>& stream) { + if (availability_state_ == STATE_DRAINING) + return; + + write_queue_.Enqueue(priority, frame_type, std::move(producer), stream); + MaybePostWriteLoop(); +} + +void SpdySession::InsertCreatedStream(std::unique_ptr<SpdyStream> stream) { + CHECK_EQ(stream->stream_id(), 0u); + CHECK(created_streams_.find(stream.get()) == created_streams_.end()); + created_streams_.insert(stream.release()); +} + +std::unique_ptr<SpdyStream> SpdySession::ActivateCreatedStream( + SpdyStream* stream) { + CHECK_EQ(stream->stream_id(), 0u); + CHECK(created_streams_.find(stream) != created_streams_.end()); + stream->set_stream_id(GetNewStreamId()); + std::unique_ptr<SpdyStream> owned_stream(stream); + created_streams_.erase(stream); + return owned_stream; +} + +void SpdySession::InsertActivatedStream(std::unique_ptr<SpdyStream> stream) { + SpdyStreamId stream_id = stream->stream_id(); + CHECK_NE(stream_id, 0u); + std::pair<ActiveStreamMap::iterator, bool> result = + active_streams_.insert(std::make_pair(stream_id, stream.get())); + CHECK(result.second); + ignore_result(stream.release()); +} + +void SpdySession::DeleteStream(std::unique_ptr<SpdyStream> stream, int status) { + if (in_flight_write_stream_.get() == stream.get()) { + // If we're deleting the stream for the in-flight write, we still + // need to let the write complete, so we clear + // |in_flight_write_stream_| and let the write finish on its own + // without notifying |in_flight_write_stream_|. + in_flight_write_stream_.reset(); + } + + write_queue_.RemovePendingWritesForStream(stream->GetWeakPtr()); + stream->OnClose(status); + + if (availability_state_ == STATE_AVAILABLE) { + ProcessPendingStreamRequests(); + } +} + +SpdyStreamId SpdySession::GetStreamIdForPush(const GURL& url) { + UnclaimedPushedStreamContainer::const_iterator unclaimed_it = + unclaimed_pushed_streams_.find(url); + if (unclaimed_it == unclaimed_pushed_streams_.end()) + return 0; + return unclaimed_it->second.stream_id; +} + +SpdyStream* SpdySession::GetActivePushStream(const GURL& url) { + UnclaimedPushedStreamContainer::const_iterator unclaimed_it = + unclaimed_pushed_streams_.find(url); + if (unclaimed_it == unclaimed_pushed_streams_.end()) + return nullptr; + + SpdyStreamId stream_id = unclaimed_it->second.stream_id; + unclaimed_pushed_streams_.erase(unclaimed_it); + + ActiveStreamMap::iterator active_it = active_streams_.find(stream_id); + if (active_it == active_streams_.end()) { + NOTREACHED(); + return nullptr; + } + + net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_ADOPTED_PUSH_STREAM, + base::Bind(&NetLogSpdyAdoptedPushStreamCallback, + active_it->second->stream_id(), &url)); + return active_it->second; +} + void SpdySession::RecordPingRTTHistogram(base::TimeDelta duration) { UMA_HISTOGRAM_CUSTOM_TIMES("Net.SpdyPing.RTT", duration, base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10), 100); } -void SpdySession::RecordProtocolErrorHistogram( - SpdyProtocolErrorDetails details) { - UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionErrorDetails2", details, - NUM_SPDY_PROTOCOL_ERROR_DETAILS); - if (base::EndsWith(host_port_pair().host(), "google.com", - base::CompareCase::INSENSITIVE_ASCII)) { - UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionErrorDetails_Google2", details, - NUM_SPDY_PROTOCOL_ERROR_DETAILS); - } -} - void SpdySession::RecordHistograms() { UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPerSession", streams_initiated_count_, 1, 300, 50); @@ -2952,6 +2363,102 @@ bytes_pushed_and_unclaimed_count_); } +void SpdySession::RecordProtocolErrorHistogram( + SpdyProtocolErrorDetails details) { + UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionErrorDetails2", details, + NUM_SPDY_PROTOCOL_ERROR_DETAILS); + if (base::EndsWith(host_port_pair().host(), "google.com", + base::CompareCase::INSENSITIVE_ASCII)) { + UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionErrorDetails_Google2", details, + NUM_SPDY_PROTOCOL_ERROR_DETAILS); + } +} + +void SpdySession::DcheckGoingAway() const { +#if DCHECK_IS_ON() + DCHECK_GE(availability_state_, STATE_GOING_AWAY); + for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) { + DCHECK(pending_create_stream_queues_[i].empty()); + } + DCHECK(created_streams_.empty()); +#endif +} + +void SpdySession::DcheckDraining() const { + DcheckGoingAway(); + DCHECK_EQ(availability_state_, STATE_DRAINING); + DCHECK(active_streams_.empty()); + DCHECK(unclaimed_pushed_streams_.empty()); +} + +void SpdySession::DoDrainSession(Error err, const std::string& description) { + if (availability_state_ == STATE_DRAINING) { + return; + } + MakeUnavailable(); + + // Mark host_port_pair requiring HTTP/1.1 for subsequent connections. + if (err == ERR_HTTP_1_1_REQUIRED) { + http_server_properties_->SetHTTP11Required(host_port_pair()); + } + + // If |err| indicates an error occurred, inform the peer that we're closing + // and why. Don't GOAWAY on a graceful or idle close, as that may + // unnecessarily wake the radio. We could technically GOAWAY on network errors + // (we'll probably fail to actually write it, but that's okay), however many + // unit-tests would need to be updated. + if (err != OK && + err != ERR_ABORTED && // Used by SpdySessionPool to close idle sessions. + err != ERR_NETWORK_CHANGED && // Used to deprecate sessions on IP change. + err != ERR_SOCKET_NOT_CONNECTED && err != ERR_HTTP_1_1_REQUIRED && + err != ERR_CONNECTION_CLOSED && err != ERR_CONNECTION_RESET) { + // Enqueue a GOAWAY to inform the peer of why we're closing the connection. + SpdyGoAwayIR goaway_ir(last_accepted_push_stream_id_, + MapNetErrorToGoAwayStatus(err), description); + EnqueueSessionWrite( + HIGHEST, GOAWAY, + std::unique_ptr<SpdySerializedFrame>(new SpdySerializedFrame( + buffered_spdy_framer_->SerializeFrame(goaway_ir)))); + } + + availability_state_ = STATE_DRAINING; + error_on_close_ = err; + + net_log_.AddEvent( + NetLogEventType::HTTP2_SESSION_CLOSE, + base::Bind(&NetLogSpdySessionCloseCallback, err, &description)); + + UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SpdySession.ClosedOnError", -err); + + if (err == OK) { + // We ought to be going away already, as this is a graceful close. + DcheckGoingAway(); + } else { + StartGoingAway(0, err); + } + DcheckDraining(); + MaybePostWriteLoop(); +} + +void SpdySession::LogAbandonedStream(SpdyStream* stream, Error status) { + DCHECK(stream); + std::string description = + base::StringPrintf("ABANDONED (stream_id=%d): ", stream->stream_id()) + + stream->url().spec(); + stream->LogStreamError(status, description); + // We don't increment the streams abandoned counter here. If the + // stream isn't active (i.e., it hasn't written anything to the wire + // yet) then it's as if it never existed. If it is active, then + // LogAbandonedActiveStream() will increment the counters. +} + +void SpdySession::LogAbandonedActiveStream(ActiveStreamMap::const_iterator it, + Error status) { + DCHECK_GT(it->first, 0u); + LogAbandonedStream(it->second, status); + ++streams_abandoned_count_; +} + void SpdySession::CompleteStreamRequest( const base::WeakPtr<SpdyStreamRequest>& pending_request) { // Abort if the request has already been cancelled. @@ -2973,6 +2480,491 @@ } } +void SpdySession::DeleteExpiredPushedStreams() { + if (unclaimed_pushed_streams_.empty()) + return; + + // Check that adequate time has elapsed since the last sweep. + if (time_func_() < next_unclaimed_push_stream_sweep_time_) + return; + + // Gather old streams to delete. + base::TimeTicks minimum_freshness = + time_func_() - + base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds); + std::vector<SpdyStreamId> streams_to_close; + for (UnclaimedPushedStreamContainer::const_iterator it = + unclaimed_pushed_streams_.begin(); + it != unclaimed_pushed_streams_.end(); ++it) { + if (minimum_freshness > it->second.creation_time) + streams_to_close.push_back(it->second.stream_id); + } + + for (std::vector<SpdyStreamId>::const_iterator to_close_it = + streams_to_close.begin(); + to_close_it != streams_to_close.end(); ++to_close_it) { + ActiveStreamMap::iterator active_it = active_streams_.find(*to_close_it); + if (active_it == active_streams_.end()) + continue; + bytes_pushed_and_unclaimed_count_ += active_it->second->recv_bytes(); + + LogAbandonedActiveStream(active_it, ERR_INVALID_SPDY_STREAM); + // CloseActiveStreamIterator() will remove the stream from + // |unclaimed_pushed_streams_|. + ResetStreamIterator(active_it, ERROR_CODE_REFUSED_STREAM, + "Stream not claimed."); + } + + next_unclaimed_push_stream_sweep_time_ = + time_func_() + + base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds); +} + +void SpdySession::OnError(SpdyFramer::SpdyFramerError spdy_framer_error) { + CHECK(in_io_loop_); + + RecordProtocolErrorHistogram( + MapFramerErrorToProtocolError(spdy_framer_error)); + std::string description = base::StringPrintf( + "Framer error: %d (%s).", spdy_framer_error, + SpdyFramer::SpdyFramerErrorToString(spdy_framer_error)); + DoDrainSession(MapFramerErrorToNetError(spdy_framer_error), description); +} + +void SpdySession::OnStreamError(SpdyStreamId stream_id, + const std::string& description) { + CHECK(in_io_loop_); + + ActiveStreamMap::iterator it = active_streams_.find(stream_id); + if (it == active_streams_.end()) { + // We still want to send a frame to reset the stream even if we + // don't know anything about it. + EnqueueResetStreamFrame(stream_id, IDLE, ERROR_CODE_PROTOCOL_ERROR, + description); + return; + } + + ResetStreamIterator(it, ERROR_CODE_PROTOCOL_ERROR, description); +} + +void SpdySession::OnPing(SpdyPingId unique_id, bool is_ack) { + CHECK(in_io_loop_); + + net_log_.AddEvent( + NetLogEventType::HTTP2_SESSION_PING, + base::Bind(&NetLogSpdyPingCallback, unique_id, is_ack, "received")); + + // Send response to a PING from server. + if (!is_ack) { + WritePingFrame(unique_id, true); + return; + } + + --pings_in_flight_; + if (pings_in_flight_ < 0) { + RecordProtocolErrorHistogram(PROTOCOL_ERROR_UNEXPECTED_PING); + DoDrainSession(ERR_SPDY_PROTOCOL_ERROR, "pings_in_flight_ is < 0."); + pings_in_flight_ = 0; + return; + } + + if (pings_in_flight_ > 0) + return; + + // We will record RTT in histogram when there are no more client sent + // pings_in_flight_. + RecordPingRTTHistogram(time_func_() - last_ping_sent_time_); +} + +void SpdySession::OnRstStream(SpdyStreamId stream_id, + SpdyErrorCode error_code) { + CHECK(in_io_loop_); + + net_log().AddEvent( + NetLogEventType::HTTP2_SESSION_RECV_RST_STREAM, + base::Bind(&NetLogSpdyRecvRstStreamCallback, stream_id, error_code)); + + ActiveStreamMap::iterator it = active_streams_.find(stream_id); + if (it == active_streams_.end()) { + // NOTE: it may just be that the stream was cancelled. + LOG(WARNING) << "Received RST for invalid stream" << stream_id; + return; + } + + CHECK_EQ(it->second->stream_id(), stream_id); + + if (error_code == ERROR_CODE_NO_ERROR) { + CloseActiveStreamIterator(it, ERR_SPDY_RST_STREAM_NO_ERROR_RECEIVED); + } else if (error_code == ERROR_CODE_REFUSED_STREAM) { + CloseActiveStreamIterator(it, ERR_SPDY_SERVER_REFUSED_STREAM); + } else if (error_code == ERROR_CODE_HTTP_1_1_REQUIRED) { + // TODO(bnc): Record histogram with number of open streams capped at 50. + it->second->LogStreamError( + ERR_HTTP_1_1_REQUIRED, + base::StringPrintf( + "SPDY session closed because of stream with error_code: %u", + error_code)); + DoDrainSession(ERR_HTTP_1_1_REQUIRED, "HTTP_1_1_REQUIRED for stream."); + } else { + RecordProtocolErrorHistogram( + PROTOCOL_ERROR_RST_STREAM_FOR_NON_ACTIVE_STREAM); + it->second->LogStreamError( + ERR_SPDY_PROTOCOL_ERROR, + base::StringPrintf("SPDY stream closed with error_code: %u", + error_code)); + // TODO(mbelshe): Map from Spdy-protocol errors to something sensical. + // For now, it doesn't matter much - it is a protocol error. + CloseActiveStreamIterator(it, ERR_SPDY_PROTOCOL_ERROR); + } +} + +void SpdySession::OnGoAway(SpdyStreamId last_accepted_stream_id, + SpdyErrorCode error_code, + base::StringPiece debug_data) { + CHECK(in_io_loop_); + + // TODO(jgraettinger): UMA histogram on |error_code|. + + net_log_.AddEvent( + NetLogEventType::HTTP2_SESSION_RECV_GOAWAY, + base::Bind(&NetLogSpdyRecvGoAwayCallback, last_accepted_stream_id, + active_streams_.size(), unclaimed_pushed_streams_.size(), + error_code, debug_data)); + MakeUnavailable(); + if (error_code == ERROR_CODE_HTTP_1_1_REQUIRED) { + // TODO(bnc): Record histogram with number of open streams capped at 50. + DoDrainSession(ERR_HTTP_1_1_REQUIRED, "HTTP_1_1_REQUIRED for stream."); + } else { + StartGoingAway(last_accepted_stream_id, ERR_ABORTED); + } + // This is to handle the case when we already don't have any active + // streams (i.e., StartGoingAway() did nothing). Otherwise, we have + // active streams and so the last one being closed will finish the + // going away process (see DeleteStream()). + MaybeFinishGoingAway(); +} + +void SpdySession::OnDataFrameHeader(SpdyStreamId stream_id, + size_t length, + bool fin) { + CHECK(in_io_loop_); + + ActiveStreamMap::iterator it = active_streams_.find(stream_id); + + // By the time data comes in, the stream may already be inactive. + if (it == active_streams_.end()) + return; + + SpdyStream* stream = it->second; + CHECK_EQ(stream->stream_id(), stream_id); + + DCHECK(buffered_spdy_framer_); + size_t header_len = buffered_spdy_framer_->GetDataFrameMinimumSize(); + stream->AddRawReceivedBytes(header_len); +} + +void SpdySession::OnStreamFrameData(SpdyStreamId stream_id, + const char* data, + size_t len) { + CHECK(in_io_loop_); + DCHECK_LT(len, 1u << 24); + if (net_log().IsCapturing()) { + net_log().AddEvent( + NetLogEventType::HTTP2_SESSION_RECV_DATA, + base::Bind(&NetLogSpdyDataCallback, stream_id, len, false)); + } + + // Build the buffer as early as possible so that we go through the + // session flow control checks and update + // |unacked_recv_window_bytes_| properly even when the stream is + // inactive (since the other side has still reduced its session send + // window). + std::unique_ptr<SpdyBuffer> buffer; + if (data) { + DCHECK_GT(len, 0u); + CHECK_LE(len, static_cast<size_t>(kReadBufferSize)); + buffer.reset(new SpdyBuffer(data, len)); + + DecreaseRecvWindowSize(static_cast<int32_t>(len)); + buffer->AddConsumeCallback(base::Bind(&SpdySession::OnReadBufferConsumed, + weak_factory_.GetWeakPtr())); + } else { + DCHECK_EQ(len, 0u); + } + + ActiveStreamMap::iterator it = active_streams_.find(stream_id); + + // By the time data comes in, the stream may already be inactive. + if (it == active_streams_.end()) + return; + + SpdyStream* stream = it->second; + CHECK_EQ(stream->stream_id(), stream_id); + + stream->AddRawReceivedBytes(len); + stream->OnDataReceived(std::move(buffer)); +} + +void SpdySession::OnStreamEnd(SpdyStreamId stream_id) { + CHECK(in_io_loop_); + if (net_log().IsCapturing()) { + net_log().AddEvent(NetLogEventType::HTTP2_SESSION_RECV_DATA, + base::Bind(&NetLogSpdyDataCallback, stream_id, 0, true)); + } + + ActiveStreamMap::iterator it = active_streams_.find(stream_id); + // By the time data comes in, the stream may already be inactive. + if (it == active_streams_.end()) + return; + + SpdyStream* stream = it->second; + CHECK_EQ(stream->stream_id(), stream_id); + + stream->OnDataReceived(std::unique_ptr<SpdyBuffer>()); +} + +void SpdySession::OnStreamPadding(SpdyStreamId stream_id, size_t len) { + CHECK(in_io_loop_); + + // Decrease window size because padding bytes are received. + // Increase window size because padding bytes are consumed (by discarding). + // Net result: |session_unacked_recv_window_bytes_| increases by |len|, + // |session_recv_window_size_| does not change. + DecreaseRecvWindowSize(static_cast<int32_t>(len)); + IncreaseRecvWindowSize(static_cast<int32_t>(len)); + + ActiveStreamMap::iterator it = active_streams_.find(stream_id); + if (it == active_streams_.end()) + return; + it->second->OnPaddingConsumed(len); +} + +void SpdySession::OnSettings() { + CHECK(in_io_loop_); + + if (net_log_.IsCapturing()) { + net_log_.AddEvent( + NetLogEventType::HTTP2_SESSION_RECV_SETTINGS, + base::Bind(&NetLogSpdyRecvSettingsCallback, host_port_pair())); + } + + // Send an acknowledgment of the setting. + SpdySettingsIR settings_ir; + settings_ir.set_is_ack(true); + EnqueueSessionWrite( + HIGHEST, SETTINGS, + std::unique_ptr<SpdySerializedFrame>(new SpdySerializedFrame( + buffered_spdy_framer_->SerializeFrame(settings_ir)))); +} + +void SpdySession::OnSetting(SpdySettingsIds id, uint32_t value) { + CHECK(in_io_loop_); + + HandleSetting(id, value); + + // Log the setting. + net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_SETTING, + base::Bind(&NetLogSpdyRecvSettingCallback, id, value)); +} + +void SpdySession::OnWindowUpdate(SpdyStreamId stream_id, + int delta_window_size) { + CHECK(in_io_loop_); + + net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_WINDOW_UPDATE, + base::Bind(&NetLogSpdyWindowUpdateFrameCallback, stream_id, + delta_window_size)); + + if (stream_id == kSessionFlowControlStreamId) { + // WINDOW_UPDATE for the session. + if (delta_window_size < 1) { + RecordProtocolErrorHistogram(PROTOCOL_ERROR_INVALID_WINDOW_UPDATE_SIZE); + DoDrainSession( + ERR_SPDY_PROTOCOL_ERROR, + "Received WINDOW_UPDATE with an invalid delta_window_size " + + base::IntToString(delta_window_size)); + return; + } + + IncreaseSendWindowSize(delta_window_size); + } else { + // WINDOW_UPDATE for a stream. + ActiveStreamMap::iterator it = active_streams_.find(stream_id); + + if (it == active_streams_.end()) { + // NOTE: it may just be that the stream was cancelled. + LOG(WARNING) << "Received WINDOW_UPDATE for invalid stream " << stream_id; + return; + } + + SpdyStream* stream = it->second; + CHECK_EQ(stream->stream_id(), stream_id); + + if (delta_window_size < 1) { + ResetStreamIterator( + it, ERROR_CODE_FLOW_CONTROL_ERROR, + base::StringPrintf("Received WINDOW_UPDATE with an invalid " + "delta_window_size %d", + delta_window_size)); + return; + } + + CHECK_EQ(it->second->stream_id(), stream_id); + it->second->IncreaseSendWindowSize(delta_window_size); + } +} + +void SpdySession::OnPushPromise(SpdyStreamId stream_id, + SpdyStreamId promised_stream_id, + SpdyHeaderBlock headers) { + CHECK(in_io_loop_); + + if (net_log_.IsCapturing()) { + net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_PUSH_PROMISE, + base::Bind(&NetLogSpdyPushPromiseReceivedCallback, + &headers, stream_id, promised_stream_id)); + } + + TryCreatePushStream(promised_stream_id, stream_id, std::move(headers)); +} + +void SpdySession::OnHeaders(SpdyStreamId stream_id, + bool has_priority, + int weight, + SpdyStreamId parent_stream_id, + bool exclusive, + bool fin, + SpdyHeaderBlock headers) { + CHECK(in_io_loop_); + + if (net_log().IsCapturing()) { + net_log().AddEvent(NetLogEventType::HTTP2_SESSION_RECV_HEADERS, + base::Bind(&NetLogSpdyHeadersReceivedCallback, &headers, + fin, stream_id)); + } + + ActiveStreamMap::iterator it = active_streams_.find(stream_id); + if (it == active_streams_.end()) { + // NOTE: it may just be that the stream was cancelled. + LOG(WARNING) << "Received HEADERS for invalid stream " << stream_id; + return; + } + + SpdyStream* stream = it->second; + CHECK_EQ(stream->stream_id(), stream_id); + + stream->AddRawReceivedBytes(last_compressed_frame_len_); + last_compressed_frame_len_ = 0; + + if (it->second->IsReservedRemote()) { + DCHECK_EQ(SPDY_PUSH_STREAM, stream->type()); + if (max_concurrent_pushed_streams_ && + num_active_pushed_streams_ >= max_concurrent_pushed_streams_) { + ResetStream(stream_id, ERROR_CODE_REFUSED_STREAM, + "Stream concurrency limit reached."); + return; + } + + // Will be balanced in DeleteStream. + num_active_pushed_streams_++; + } + + base::Time response_time = base::Time::Now(); + base::TimeTicks recv_first_byte_time = time_func_(); + // May invalidate |stream|. + stream->OnHeadersReceived(headers, response_time, recv_first_byte_time); +} + +void SpdySession::OnAltSvc( + SpdyStreamId stream_id, + base::StringPiece origin, + const SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector) { + if (!is_secure_) + return; + + url::SchemeHostPort scheme_host_port; + if (stream_id == 0) { + if (origin.empty()) + return; + const GURL gurl(origin); + if (!gurl.SchemeIs("https")) + return; + SSLInfo ssl_info; + if (!GetSSLInfo(&ssl_info)) + return; + if (!CanPool(transport_security_state_, ssl_info, host_port_pair().host(), + gurl.host())) { + return; + } + scheme_host_port = url::SchemeHostPort(gurl); + } else { + if (!origin.empty()) + return; + const ActiveStreamMap::iterator it = active_streams_.find(stream_id); + if (it == active_streams_.end()) + return; + const GURL& gurl(it->second->url()); + if (!gurl.SchemeIs("https")) + return; + scheme_host_port = url::SchemeHostPort(gurl); + } + + AlternativeServiceInfoVector alternative_service_info_vector; + alternative_service_info_vector.reserve(altsvc_vector.size()); + const base::Time now(base::Time::Now()); + for (const SpdyAltSvcWireFormat::AlternativeService& altsvc : altsvc_vector) { + const NextProto protocol = NextProtoFromString(altsvc.protocol_id); + if (protocol == kProtoUnknown) + continue; + const AlternativeService alternative_service(protocol, altsvc.host, + altsvc.port); + const base::Time expiration = + now + base::TimeDelta::FromSeconds(altsvc.max_age); + alternative_service_info_vector.push_back( + AlternativeServiceInfo(alternative_service, expiration)); + } + http_server_properties_->SetAlternativeServices( + scheme_host_port, alternative_service_info_vector); +} + +bool SpdySession::OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) { + // Validate stream id. + // Was the frame sent on a stream id that has not been used in this session? + if (stream_id % 2 == 1 && stream_id > stream_hi_water_mark_) + return false; + + if (stream_id % 2 == 0 && stream_id > last_accepted_push_stream_id_) + return false; + + return true; +} + +void SpdySession::OnSendCompressedFrame(SpdyStreamId stream_id, + SpdyFrameType type, + size_t payload_len, + size_t frame_len) { + if (type != HEADERS) { + return; + } + + DCHECK(buffered_spdy_framer_.get()); + size_t compressed_len = + frame_len - buffered_spdy_framer_->GetFrameMinimumSize(); + + if (payload_len) { + // Make sure we avoid early decimal truncation. + int compression_pct = 100 - (100 * compressed_len) / payload_len; + UMA_HISTOGRAM_PERCENTAGE("Net.SpdyHeadersCompressionPercentage", + compression_pct); + } +} + +void SpdySession::OnReceiveCompressedFrame(SpdyStreamId stream_id, + SpdyFrameType type, + size_t frame_len) { + last_compressed_frame_len_ = frame_len; +} + void SpdySession::OnWriteBufferConsumed( size_t frame_payload_size, size_t consume_size, @@ -3066,8 +3058,7 @@ session_unacked_recv_window_bytes_ += delta_window_size; if (session_unacked_recv_window_bytes_ > session_max_recv_window_size_ / 2) { SendWindowUpdateFrame(kSessionFlowControlStreamId, - session_unacked_recv_window_bytes_, - HIGHEST); + session_unacked_recv_window_bytes_, HIGHEST); session_unacked_recv_window_bytes_ = 0; } }
diff --git a/net/test/android/net_test_entry_point.cc b/net/test/android/net_test_entry_point.cc index c7a2dde0..fa324cb 100644 --- a/net/test/android/net_test_entry_point.cc +++ b/net/test/android/net_test_entry_point.cc
@@ -7,7 +7,10 @@ // This is called by the VM when the shared library is first loaded. JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { - if (!net::test::OnJNIOnLoadRegisterJNI(vm) || !net::test::OnJNIOnLoadInit()) { + base::android::InitVM(vm); + JNIEnv* env = base::android::AttachCurrentThread(); + if (!net::test::OnJNIOnLoadRegisterJNI(env) || + !net::test::OnJNIOnLoadInit()) { return -1; } return JNI_VERSION_1_4;
diff --git a/net/test/android/net_test_jni_onload.cc b/net/test/android/net_test_jni_onload.cc index 6f3db27..0f0e5a6 100644 --- a/net/test/android/net_test_jni_onload.cc +++ b/net/test/android/net_test_jni_onload.cc
@@ -6,6 +6,7 @@ #include "base/android/base_jni_onload.h" #include "base/android/base_jni_registrar.h" +#include "base/android/jni_android.h" #include "base/bind.h" #include "net/test/embedded_test_server/android/embedded_test_server_android.h" @@ -19,23 +20,15 @@ RegisterEmbeddedTestServerAndroid(env); } -bool Init() { - return true; -} - } // namesapce -bool OnJNIOnLoadRegisterJNI(JavaVM* vm) { - std::vector<base::android::RegisterCallback> register_callbacks; - register_callbacks.push_back(base::Bind(&RegisterJNI)); - register_callbacks.push_back(base::Bind(&base::android::RegisterJni)); - return base::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks); +bool OnJNIOnLoadRegisterJNI(JNIEnv* env) { + return base::android::OnJNIOnLoadRegisterJNI(env) && + base::android::RegisterJni(env) && RegisterJNI(env); } bool OnJNIOnLoadInit() { - std::vector<base::android::InitCallback> init_callbacks; - init_callbacks.push_back(base::Bind(&Init)); - return base::android::OnJNIOnLoadInit(init_callbacks); + return base::android::OnJNIOnLoadInit(); } } // namespace test
diff --git a/net/test/android/net_test_jni_onload.h b/net/test/android/net_test_jni_onload.h index 67d139a..680dbf8 100644 --- a/net/test/android/net_test_jni_onload.h +++ b/net/test/android/net_test_jni_onload.h
@@ -10,7 +10,7 @@ namespace net { namespace test { -bool OnJNIOnLoadRegisterJNI(JavaVM* vm); +bool OnJNIOnLoadRegisterJNI(JNIEnv* env); bool OnJNIOnLoadInit(); } // namespace test
diff --git a/net/tools/quic/chlo_extractor_test.cc b/net/tools/quic/chlo_extractor_test.cc index bdce1b8..299e05d9 100644 --- a/net/tools/quic/chlo_extractor_test.cc +++ b/net/tools/quic/chlo_extractor_test.cc
@@ -63,9 +63,9 @@ std::unique_ptr<QuicPacket> packet( BuildUnsizedDataPacket(&framer, header_, frames)); EXPECT_TRUE(packet != nullptr); - size_t encrypted_length = framer.EncryptPayload( - ENCRYPTION_NONE, header_.path_id, header_.packet_number, *packet, - buffer_, arraysize(buffer_)); + size_t encrypted_length = + framer.EncryptPayload(ENCRYPTION_NONE, header_.packet_number, *packet, + buffer_, arraysize(buffer_)); ASSERT_NE(0u, encrypted_length); packet_.reset(new QuicEncryptedPacket(buffer_, encrypted_length)); EXPECT_TRUE(packet_ != nullptr);
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc index 93e499d..31cf5f0 100644 --- a/net/tools/quic/end_to_end_test.cc +++ b/net/tools/quic/end_to_end_test.cc
@@ -318,9 +318,10 @@ } QuicTestClient* CreateQuicClient(QuicPacketWriterWrapper* writer) { - QuicTestClient* client = new QuicTestClient( - server_address_, server_hostname_, client_config_, - client_supported_versions_, CryptoTestUtils::ProofVerifierForTesting()); + QuicTestClient* client = + new QuicTestClient(server_address_, server_hostname_, client_config_, + client_supported_versions_, + crypto_test_utils::ProofVerifierForTesting()); client->UseWriter(writer); client->Connect(); return client; @@ -439,7 +440,7 @@ GetParam().use_cheap_stateless_reject; auto test_server = new QuicTestServer( - CryptoTestUtils::ProofSourceForTesting(), server_config_, + crypto_test_utils::ProofSourceForTesting(), server_config_, server_supported_versions_, &response_cache_); server_thread_.reset(new ServerThread(test_server, server_address_)); if (chlo_multiplier_ != 0) {
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc index d463e87..37492b1 100644 --- a/net/tools/quic/quic_client_session_test.cc +++ b/net/tools/quic/quic_client_session_test.cc
@@ -65,7 +65,7 @@ class QuicClientSessionTest : public ::testing::TestWithParam<QuicVersion> { protected: QuicClientSessionTest() - : crypto_config_(CryptoTestUtils::ProofVerifierForTesting()), + : crypto_config_(crypto_test_utils::ProofVerifierForTesting()), promised_stream_id_(kServerDataStreamId1), associated_stream_id_(kClientDataStreamId1) { Initialize(); @@ -104,11 +104,11 @@ session_->CryptoConnect(); QuicCryptoClientStream* stream = static_cast<QuicCryptoClientStream*>(session_->GetCryptoStream()); - CryptoTestUtils::FakeServerOptions options; + crypto_test_utils::FakeServerOptions options; QuicConfig config = DefaultQuicConfig(); config.SetMaxIncomingDynamicStreamsToSend(server_max_incoming_streams); - CryptoTestUtils::HandshakeWithFakeServer(&config, &helper_, &alarm_factory_, - connection_, stream, options); + crypto_test_utils::HandshakeWithFakeServer( + &config, &helper_, &alarm_factory_, connection_, stream, options); } QuicCryptoClientConfig crypto_config_; @@ -151,7 +151,7 @@ // an inchoate CHLO to be sent and will leave the encryption level // at NONE. CryptoHandshakeMessage rej; - CryptoTestUtils::FillInDummyReject(&rej, /* stateless */ false); + crypto_test_utils::FillInDummyReject(&rej, /* stateless */ false); EXPECT_TRUE(session_->IsEncryptionEstablished()); session_->GetCryptoStream()->OnHandshakeMessage(rej); EXPECT_FALSE(session_->IsEncryptionEstablished());
diff --git a/net/tools/quic/quic_client_test.cc b/net/tools/quic/quic_client_test.cc index 1037aedc..313c23f 100644 --- a/net/tools/quic/quic_client_test.cc +++ b/net/tools/quic/quic_client_test.cc
@@ -55,7 +55,7 @@ QuicVersionVector versions = AllSupportedVersions(); QuicClient* client = new QuicClient(server_address, server_id, versions, eps, - CryptoTestUtils::ProofVerifierForTesting()); + crypto_test_utils::ProofVerifierForTesting()); EXPECT_TRUE(client->Initialize()); return client; } @@ -66,7 +66,7 @@ // Create a ProofVerifier before counting the number of open FDs to work // around some ASAN weirdness. - CryptoTestUtils::ProofVerifierForTesting().reset(); + crypto_test_utils::ProofVerifierForTesting().reset(); // Make sure that the QuicClient doesn't leak FDs. Doing so could cause port // exhaustion in long running processes which repeatedly create clients. @@ -93,7 +93,7 @@ TEST(QuicClientTest, CreateAndCleanUpUDPSockets) { // Create a ProofVerifier before counting the number of open FDs to work // around some ASAN weirdness. - CryptoTestUtils::ProofVerifierForTesting().reset(); + crypto_test_utils::ProofVerifierForTesting().reset(); EpollServer eps; size_t number_of_open_fds = NumOpenSocketFDs();
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc index fd24d8b..fe650dc 100644 --- a/net/tools/quic/quic_dispatcher.cc +++ b/net/tools/quic/quic_dispatcher.cc
@@ -276,9 +276,8 @@ } // Check if we are buffering packets for this connection ID - if (FLAGS_quic_reloadable_flag_enable_async_get_proof && - (temporarily_buffered_connections_.find(connection_id) != - temporarily_buffered_connections_.end())) { + if (temporarily_buffered_connections_.find(connection_id) != + temporarily_buffered_connections_.end()) { // This packet was received while the a CHLO for the same connection ID was // being processed. Buffer it. BufferEarlyPacket(connection_id); @@ -386,14 +385,11 @@ current_server_address_, current_client_address_, connection_id, packet_number, *current_packet_); - if (FLAGS_quic_reloadable_flag_enable_async_get_proof) { - // Any packets which were buffered while the stateless rejector logic - // was running should be discarded. Do not inform the time wait list - // manager, which should already have a made a decision about sending a - // reject based on the CHLO alone. - buffered_packets_.DiscardPackets(connection_id); - } - + // Any packets which were buffered while the stateless rejector logic was + // running should be discarded. Do not inform the time wait list manager, + // which should already have a made a decision about sending a reject + // based on the CHLO alone. + buffered_packets_.DiscardPackets(connection_id); break; case kFateBuffer: // This packet is a non-CHLO packet which has arrived before the @@ -888,13 +884,11 @@ } // Insert into set of connection IDs to buffer - if (FLAGS_quic_reloadable_flag_enable_async_get_proof) { - const bool ok = - temporarily_buffered_connections_.insert(connection_id).second; - QUIC_BUG_IF(!ok) - << "Processing multiple stateless rejections for connection ID " - << connection_id; - } + const bool ok = + temporarily_buffered_connections_.insert(connection_id).second; + QUIC_BUG_IF(!ok) + << "Processing multiple stateless rejections for connection ID " + << connection_id; // Continue stateless rejector processing std::unique_ptr<StatelessRejectorProcessDoneCallback> cb( @@ -910,23 +904,21 @@ std::unique_ptr<QuicReceivedPacket> current_packet, QuicPacketNumber packet_number, QuicVersion first_version) { - if (FLAGS_quic_reloadable_flag_enable_async_get_proof) { - // Stop buffering packets on this connection - const auto num_erased = - temporarily_buffered_connections_.erase(rejector->connection_id()); - QUIC_BUG_IF(num_erased != 1) << "Completing stateless rejection logic for " - "non-buffered connection ID " - << rejector->connection_id(); + // Stop buffering packets on this connection + const auto num_erased = + temporarily_buffered_connections_.erase(rejector->connection_id()); + QUIC_BUG_IF(num_erased != 1) << "Completing stateless rejection logic for " + "non-buffered connection ID " + << rejector->connection_id(); - // If this connection has gone into time-wait during the async processing, - // don't proceed. - if (time_wait_list_manager_->IsConnectionIdInTimeWait( - rejector->connection_id())) { - time_wait_list_manager_->ProcessPacket( - current_server_address, current_client_address, - rejector->connection_id(), packet_number, *current_packet); - return; - } + // If this connection has gone into time-wait during the async processing, + // don't proceed. + if (time_wait_list_manager_->IsConnectionIdInTimeWait( + rejector->connection_id())) { + time_wait_list_manager_->ProcessPacket( + current_server_address, current_client_address, + rejector->connection_id(), packet_number, *current_packet); + return; } // Reset current_* to correspond to the packet which initiated the stateless
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc index 456622e9..257ad13 100644 --- a/net/tools/quic/quic_dispatcher_test.cc +++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -166,7 +166,7 @@ class QuicDispatcherTest : public ::testing::Test { public: QuicDispatcherTest() - : QuicDispatcherTest(CryptoTestUtils::ProofSourceForTesting()) {} + : QuicDispatcherTest(crypto_test_utils::ProofSourceForTesting()) {} explicit QuicDispatcherTest(std::unique_ptr<ProofSource> proof_source) : helper_(&eps_, QuicAllocator::BUFFER_POOL), @@ -819,17 +819,13 @@ QUIC_LOG(INFO) << "ExpectStatelessReject: " << ExpectStatelessReject(); QUIC_LOG(INFO) << "Params: " << GetParam(); // Process the first packet for the connection. - // clang-format off - CryptoHandshakeMessage client_hello = CryptoTestUtils::Message( - "CHLO", - "AEAD", "AESG", - "KEXS", "C255", - "COPT", "SREJ", - "NONC", "1234567890123456789012", - "VER\0", "Q025", - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage client_hello = + crypto_test_utils::CreateCHLO({{"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"COPT", "SREJ"}, + {"NONC", "1234567890123456789012"}, + {"VER\0", "Q025"}}, + kClientHelloMinimumSize); ProcessPacket(client_address, connection_id, true, false, client_hello.GetSerialized().AsStringPiece().as_string()); @@ -851,16 +847,12 @@ "NOT DATA FOR A CHLO"); // Process the first packet for the connection. - // clang-format off - CryptoHandshakeMessage client_hello = CryptoTestUtils::Message( - "CHLO", - "AEAD", "AESG", - "KEXS", "C255", - "NONC", "1234567890123456789012", - "VER\0", "Q025", - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on + CryptoHandshakeMessage client_hello = + crypto_test_utils::CreateCHLO({{"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"NONC", "1234567890123456789012"}, + {"VER\0", "Q025"}}, + kClientHelloMinimumSize); // If stateless rejects are enabled then a connection will be created now // and the buffered packet will be processed @@ -1170,11 +1162,12 @@ clock_ = QuicDispatcherPeer::GetHelper(dispatcher_.get())->GetClock(); QuicVersion version = AllSupportedVersions().front(); - CryptoHandshakeMessage chlo = CryptoTestUtils::GenerateDefaultInchoateCHLO( - clock_, version, &crypto_config_); + CryptoHandshakeMessage chlo = + crypto_test_utils::GenerateDefaultInchoateCHLO(clock_, version, + &crypto_config_); chlo.SetVector(net::kCOPT, net::QuicTagVector{net::kSREJ}); // Pass an inchoate CHLO. - CryptoTestUtils::GenerateFullCHLO( + crypto_test_utils::GenerateFullCHLO( chlo, &crypto_config_, server_addr_, client_addr_, version, clock_, signed_config_, QuicDispatcherPeer::GetCache(dispatcher_.get()), &full_chlo_); @@ -1610,7 +1603,6 @@ client_addr_(QuicIpAddress::Loopback4(), 1234), crypto_config_peer_(&crypto_config_), signed_config_(new QuicSignedServerConfig) { - FLAGS_quic_reloadable_flag_enable_async_get_proof = true; FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support = true; FLAGS_quic_reloadable_flag_quic_use_cheap_stateless_rejects = true; FLAGS_quic_reloadable_flag_quic_create_session_after_insertion = true; @@ -1621,11 +1613,11 @@ clock_ = QuicDispatcherPeer::GetHelper(dispatcher_.get())->GetClock(); QuicVersion version = AllSupportedVersions().front(); - chlo_ = CryptoTestUtils::GenerateDefaultInchoateCHLO(clock_, version, - &crypto_config_); + chlo_ = crypto_test_utils::GenerateDefaultInchoateCHLO(clock_, version, + &crypto_config_); chlo_.SetVector(net::kCOPT, net::QuicTagVector{net::kSREJ}); // Pass an inchoate CHLO. - CryptoTestUtils::GenerateFullCHLO( + crypto_test_utils::GenerateFullCHLO( chlo_, &crypto_config_, server_addr_, client_addr_, version, clock_, signed_config_, QuicDispatcherPeer::GetCache(dispatcher_.get()), &full_chlo_);
diff --git a/net/tools/quic/quic_server_test.cc b/net/tools/quic/quic_server_test.cc index 8c6584e..dc2a94c9 100644 --- a/net/tools/quic/quic_server_test.cc +++ b/net/tools/quic/quic_server_test.cc
@@ -51,8 +51,8 @@ class TestQuicServer : public QuicServer { public: TestQuicServer() - : QuicServer(CryptoTestUtils::ProofSourceForTesting(), &response_cache_) { - } + : QuicServer(crypto_test_utils::ProofSourceForTesting(), + &response_cache_) {} ~TestQuicServer() override {} @@ -147,7 +147,7 @@ QuicServerDispatchPacketTest() : crypto_config_("blah", QuicRandom::GetInstance(), - CryptoTestUtils::ProofSourceForTesting()), + crypto_test_utils::ProofSourceForTesting()), version_manager_(AllSupportedVersions()), dispatcher_( config_,
diff --git a/net/tools/quic/quic_simple_client_test.cc b/net/tools/quic/quic_simple_client_test.cc index 64db2d2..997890e0 100644 --- a/net/tools/quic/quic_simple_client_test.cc +++ b/net/tools/quic/quic_simple_client_test.cc
@@ -18,7 +18,7 @@ PRIVACY_MODE_DISABLED); QuicVersionVector versions = AllSupportedVersions(); QuicSimpleClient client(server_address, server_id, versions, - CryptoTestUtils::ProofVerifierForTesting()); + crypto_test_utils::ProofVerifierForTesting()); EXPECT_TRUE(client.Initialize()); }
diff --git a/net/tools/quic/quic_simple_server_session_test.cc b/net/tools/quic/quic_simple_server_session_test.cc index 2ee35bb..37317065 100644 --- a/net/tools/quic/quic_simple_server_session_test.cc +++ b/net/tools/quic/quic_simple_server_session_test.cc
@@ -181,7 +181,7 @@ QuicSimpleServerSessionTest() : crypto_config_(QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), - CryptoTestUtils::ProofSourceForTesting()), + crypto_test_utils::ProofSourceForTesting()), compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) { config_.SetMaxStreamsPerConnection(kMaxStreamsForTest, kMaxStreamsForTest);
diff --git a/net/tools/quic/quic_simple_server_stream_test.cc b/net/tools/quic/quic_simple_server_stream_test.cc index bd1780e..81ced2e 100644 --- a/net/tools/quic/quic_simple_server_stream_test.cc +++ b/net/tools/quic/quic_simple_server_stream_test.cc
@@ -186,7 +186,7 @@ crypto_config_(new QuicCryptoServerConfig( QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), - ::net::test::CryptoTestUtils::ProofSourceForTesting())), + crypto_test_utils::ProofSourceForTesting())), compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), session_(connection_,
diff --git a/net/tools/quic/quic_simple_server_test.cc b/net/tools/quic/quic_simple_server_test.cc index 87969d82..58cd14e 100644 --- a/net/tools/quic/quic_simple_server_test.cc +++ b/net/tools/quic/quic_simple_server_test.cc
@@ -24,7 +24,7 @@ QuicChromeServerDispatchPacketTest() : crypto_config_("blah", QuicRandom::GetInstance(), - CryptoTestUtils::ProofSourceForTesting()), + crypto_test_utils::ProofSourceForTesting()), version_manager_(AllSupportedVersions()), dispatcher_( config_,
diff --git a/net/tools/quic/quic_spdy_client_stream_test.cc b/net/tools/quic/quic_spdy_client_stream_test.cc index b7233dff..c7140860 100644 --- a/net/tools/quic/quic_spdy_client_stream_test.cc +++ b/net/tools/quic/quic_spdy_client_stream_test.cc
@@ -38,7 +38,7 @@ QuicServerId("example.com", 443, PRIVACY_MODE_DISABLED), &crypto_config_, push_promise_index), - crypto_config_(CryptoTestUtils::ProofVerifierForTesting()) {} + crypto_config_(crypto_test_utils::ProofVerifierForTesting()) {} ~MockQuicClientSession() override {} MOCK_METHOD1(CloseStream, void(QuicStreamId stream_id));
diff --git a/net/tools/quic/stateless_rejector_test.cc b/net/tools/quic/stateless_rejector_test.cc index 23b6e3a..0076c13 100644 --- a/net/tools/quic/stateless_rejector_test.cc +++ b/net/tools/quic/stateless_rejector_test.cc
@@ -74,10 +74,10 @@ class StatelessRejectorTest : public ::testing::TestWithParam<TestParams> { public: StatelessRejectorTest() - : proof_source_(CryptoTestUtils::ProofSourceForTesting()), + : proof_source_(crypto_test_utils::ProofSourceForTesting()), config_(QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), - CryptoTestUtils::ProofSourceForTesting()), + crypto_test_utils::ProofSourceForTesting()), config_peer_(&config_), compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), @@ -170,11 +170,9 @@ TEST_P(StatelessRejectorTest, InvalidChlo) { // clang-format off - const CryptoHandshakeMessage client_hello = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "COPT", "SREJ", - nullptr); + const CryptoHandshakeMessage client_hello = crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, + {"COPT", "SREJ"}}); // clang-format on rejector_->OnChlo(GetParam().version, kConnectionId, kServerDesignateConnectionId, client_hello); @@ -195,16 +193,14 @@ TEST_P(StatelessRejectorTest, ValidChloWithoutSrejSupport) { // clang-format off - const CryptoHandshakeMessage client_hello = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "AEAD", "AESG", - "KEXS", "C255", - "PUBS", pubs_hex_.c_str(), - "NONC", nonc_hex_.c_str(), - "VER\0", ver_hex_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); + const CryptoHandshakeMessage client_hello = crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"PUBS", pubs_hex_}, + {"NONC", nonc_hex_}, + {"VER\0", ver_hex_}}, + kClientHelloMinimumSize); // clang-format on rejector_->OnChlo(GetParam().version, kConnectionId, @@ -214,19 +210,17 @@ TEST_P(StatelessRejectorTest, RejectChlo) { // clang-format off - const CryptoHandshakeMessage client_hello = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "AEAD", "AESG", - "KEXS", "C255", - "COPT", "SREJ", - "SCID", scid_hex_.c_str(), - "PUBS", pubs_hex_.c_str(), - "NONC", nonc_hex_.c_str(), - "#004b5453", stk_hex_.c_str(), - "VER\0", ver_hex_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); + const CryptoHandshakeMessage client_hello = crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"COPT", "SREJ"}, + {"SCID", scid_hex_}, + {"PUBS", pubs_hex_}, + {"NONC", nonc_hex_}, + {"#004b5453", stk_hex_}, + {"VER\0", ver_hex_}}, + kClientHelloMinimumSize); // clang-format on rejector_->OnChlo(GetParam().version, kConnectionId, @@ -254,25 +248,23 @@ } TEST_P(StatelessRejectorTest, AcceptChlo) { - const uint64_t xlct = CryptoTestUtils::LeafCertHashForTesting(); + const uint64_t xlct = crypto_test_utils::LeafCertHashForTesting(); const string xlct_hex = "#" + QuicTextUtils::HexEncode(reinterpret_cast<const char*>(&xlct), sizeof(xlct)); // clang-format off - const CryptoHandshakeMessage client_hello = CryptoTestUtils::Message( - "CHLO", - "PDMD", "X509", - "AEAD", "AESG", - "KEXS", "C255", - "COPT", "SREJ", - "SCID", scid_hex_.c_str(), - "PUBS", pubs_hex_.c_str(), - "NONC", nonc_hex_.c_str(), - "#004b5453", stk_hex_.c_str(), - "VER\0", ver_hex_.c_str(), - "XLCT", xlct_hex.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); + const CryptoHandshakeMessage client_hello = crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"COPT", "SREJ"}, + {"SCID", scid_hex_}, + {"PUBS", pubs_hex_}, + {"NONC", nonc_hex_}, + {"#004b5453", stk_hex_}, + {"VER\0", ver_hex_}, + {"XLCT", xlct_hex}}, + kClientHelloMinimumSize); // clang-format on rejector_->OnChlo(GetParam().version, kConnectionId,
diff --git a/net/url_request/url_request_quic_unittest.cc b/net/url_request/url_request_quic_unittest.cc index c285100..a713265 100644 --- a/net/url_request/url_request_quic_unittest.cc +++ b/net/url_request/url_request_quic_unittest.cc
@@ -104,7 +104,7 @@ directory.Append(FILE_PATH_LITERAL("quic_test.example.com.key.pkcs8")), directory.Append(FILE_PATH_LITERAL("quic_test.example.com.key.sct")))); server_.reset(new QuicSimpleServer( - test::CryptoTestUtils::ProofSourceForTesting(), config, + test::crypto_test_utils::ProofSourceForTesting(), config, net::QuicCryptoServerConfig::ConfigOptions(), AllSupportedVersions(), &response_cache_)); int rv = server_->Listen(
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index fa6282d..5e4e84aa 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc
@@ -7769,7 +7769,8 @@ new HttpNetworkLayer(&session)); HttpCache main_cache(std::move(network_layer1), - HttpCache::DefaultBackend::InMemory(0), true); + HttpCache::DefaultBackend::InMemory(0), + true /* is_main_cache */); EXPECT_TRUE(session.quic_stream_factory()->has_quic_server_info_factory()); @@ -7864,7 +7865,7 @@ HttpCache http_cache(std::move(network_layer), HttpCache::DefaultBackend::InMemory(0), - false /* set_up_quic_server_info_factory */); + false /* is_main_cache */); TestURLRequestContext context(true); context.set_http_transaction_factory(&http_cache); @@ -9205,8 +9206,9 @@ params.http_server_properties = default_context_.http_server_properties(); HttpNetworkSession network_session(params); - std::unique_ptr<HttpCache> cache(new HttpCache( - &network_session, HttpCache::DefaultBackend::InMemory(0), false)); + std::unique_ptr<HttpCache> cache( + new HttpCache(&network_session, HttpCache::DefaultBackend::InMemory(0), + false /* is_main_cache */)); default_context_.set_http_transaction_factory(cache.get());
diff --git a/net/url_request/view_cache_helper_unittest.cc b/net/url_request/view_cache_helper_unittest.cc index 2e28372bb..2946b18b 100644 --- a/net/url_request/view_cache_helper_unittest.cc +++ b/net/url_request/view_cache_helper_unittest.cc
@@ -38,7 +38,7 @@ TestURLRequestContext::TestURLRequestContext() : cache_(base::MakeUnique<MockNetworkLayer>(), HttpCache::DefaultBackend::InMemory(0), - false /* set_up_quic_server_info */) { + false /* is_main_cache */) { set_http_transaction_factory(&cache_); }
diff --git a/ppapi/proxy/ppapi_command_buffer_proxy.cc b/ppapi/proxy/ppapi_command_buffer_proxy.cc index 40e9d70..8a5d0622 100644 --- a/ppapi/proxy/ppapi_command_buffer_proxy.cc +++ b/ppapi/proxy/ppapi_command_buffer_proxy.cc
@@ -249,15 +249,6 @@ NOTREACHED(); } -int32_t PpapiCommandBufferProxy::CreateGpuMemoryBufferImage( - size_t width, - size_t height, - unsigned internalformat, - unsigned usage) { - NOTREACHED(); - return -1; -} - bool PpapiCommandBufferProxy::Send(IPC::Message* msg) { DCHECK(last_state_.error == gpu::error::kNoError);
diff --git a/ppapi/proxy/ppapi_command_buffer_proxy.h b/ppapi/proxy/ppapi_command_buffer_proxy.h index 24427f60..5f43ed4d 100644 --- a/ppapi/proxy/ppapi_command_buffer_proxy.h +++ b/ppapi/proxy/ppapi_command_buffer_proxy.h
@@ -59,10 +59,6 @@ size_t height, unsigned internalformat) override; void DestroyImage(int32_t id) override; - int32_t CreateGpuMemoryBufferImage(size_t width, - size_t height, - unsigned internalformat, - unsigned usage) override; void SignalQuery(uint32_t query, const base::Closure& callback) override; void SetLock(base::Lock*) override; void EnsureWorkVisible() override;
diff --git a/remoting/base/run_all_unittests.cc b/remoting/base/run_all_unittests.cc index d303a751..b20ac233 100644 --- a/remoting/base/run_all_unittests.cc +++ b/remoting/base/run_all_unittests.cc
@@ -4,12 +4,21 @@ #include "base/test/launcher/unit_test_launcher.h" #include "base/test/test_suite.h" +#include "base/threading/thread.h" #include "mojo/edk/embedder/embedder.h" +#include "mojo/edk/embedder/scoped_ipc_support.h" int main(int argc, char** argv) { base::TestSuite test_suite(argc, argv); + base::Thread ipc_thread("IPC thread"); + ipc_thread.StartWithOptions( + base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); + mojo::edk::Init(); + mojo::edk::ScopedIPCSupport ipc_support( + ipc_thread.task_runner(), + mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN); return base::LaunchUnitTests( argc, argv, base::Bind(&base::TestSuite::Run,
diff --git a/remoting/client/BUILD.gn b/remoting/client/BUILD.gn index 2c0420e..9f0063d 100644 --- a/remoting/client/BUILD.gn +++ b/remoting/client/BUILD.gn
@@ -26,6 +26,8 @@ "dual_buffer_frame_consumer.h", "empty_cursor_filter.cc", "empty_cursor_filter.h", + "host_experiment_sender.cc", + "host_experiment_sender.h", "key_event_mapper.cc", "key_event_mapper.h", "normalizing_input_filter_cros.cc",
diff --git a/remoting/client/chromoting_client.cc b/remoting/client/chromoting_client.cc index 1e5c2ca..8e8e77db 100644 --- a/remoting/client/chromoting_client.cc +++ b/remoting/client/chromoting_client.cc
@@ -31,7 +31,8 @@ ClientUserInterface* user_interface, protocol::VideoRenderer* video_renderer, base::WeakPtr<protocol::AudioStub> audio_consumer) - : user_interface_(user_interface), video_renderer_(video_renderer) { + : user_interface_(user_interface), + video_renderer_(video_renderer) { DCHECK(client_context->main_task_runner()->BelongsToCurrentThread()); audio_decode_task_runner_ = client_context->audio_decode_task_runner(); @@ -45,9 +46,18 @@ void ChromotingClient::set_protocol_config( std::unique_ptr<protocol::CandidateSessionConfig> config) { + DCHECK(!connection_) + << "set_protocol_config() cannot be called after Start()."; protocol_config_ = std::move(config); } +void ChromotingClient::set_host_experiment_config( + const std::string& experiment_config) { + DCHECK(!connection_) + << "set_host_experiment_config() cannot be called after Start()."; + host_experiment_sender_.reset(new HostExperimentSender(experiment_config)); +} + void ChromotingClient::SetConnectionToHostForTests( std::unique_ptr<protocol::ConnectionToHost> connection_to_host) { connection_ = std::move(connection_to_host); @@ -60,7 +70,7 @@ const std::string& host_jid, const std::string& capabilities) { DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(!session_manager_); // Start must be called more than once. + DCHECK(!session_manager_); // Start must not be called more than once. host_jid_ = NormalizeJid(host_jid); local_capabilities_ = capabilities; @@ -244,12 +254,14 @@ void ChromotingClient::StartConnection() { DCHECK(thread_checker_.CalledOnValidThread()); - connection_->Connect( - session_manager_->Connect( - host_jid_, base::MakeUnique<protocol::NegotiatingClientAuthenticator>( - NormalizeJid(signal_strategy_->GetLocalJid()), - host_jid_, client_auth_config_)), - transport_context_, this); + auto session = session_manager_->Connect( + host_jid_, base::MakeUnique<protocol::NegotiatingClientAuthenticator>( + NormalizeJid(signal_strategy_->GetLocalJid()), host_jid_, + client_auth_config_)); + if (host_experiment_sender_) { + session->AddPlugin(host_experiment_sender_.get()); + } + connection_->Connect(std::move(session), transport_context_, this); } void ChromotingClient::OnChannelsConnected() {
diff --git a/remoting/client/chromoting_client.h b/remoting/client/chromoting_client.h index cf8f51a8..95b3fa33 100644 --- a/remoting/client/chromoting_client.h +++ b/remoting/client/chromoting_client.h
@@ -14,6 +14,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" +#include "remoting/client/host_experiment_sender.h" #include "remoting/protocol/client_authentication_config.h" #include "remoting/protocol/client_stub.h" #include "remoting/protocol/clipboard_stub.h" @@ -57,6 +58,8 @@ void set_protocol_config( std::unique_ptr<protocol::CandidateSessionConfig> config); + void set_host_experiment_config(const std::string& experiment_config); + // Used to set fake/mock objects for tests which use the ChromotingClient. void SetConnectionToHostForTests( std::unique_ptr<protocol::ConnectionToHost> connection_to_host); @@ -139,6 +142,8 @@ // True if |protocol::Capabilities| message has been received. bool host_capabilities_received_ = false; + std::unique_ptr<HostExperimentSender> host_experiment_sender_; + DISALLOW_COPY_AND_ASSIGN(ChromotingClient); };
diff --git a/remoting/client/host_experiment_sender.cc b/remoting/client/host_experiment_sender.cc new file mode 100644 index 0000000..8ed7b5a --- /dev/null +++ b/remoting/client/host_experiment_sender.cc
@@ -0,0 +1,28 @@ +// 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 "remoting/client/host_experiment_sender.h" + +#include "remoting/base/constants.h" + +namespace remoting { + +HostExperimentSender::HostExperimentSender(const std::string& experiment_config) + : experiment_config_(experiment_config) {} + +std::unique_ptr<buzz::XmlElement> HostExperimentSender::GetNextMessage() { + if (message_sent_ || experiment_config_.empty()) { + return nullptr; + } + message_sent_ = true; + std::unique_ptr<buzz::XmlElement> configuration(new buzz::XmlElement( + buzz::QName(kChromotingXmlNamespace, "host-configuration"))); + configuration->SetBodyText(experiment_config_); + return configuration; +} + +void HostExperimentSender::OnIncomingMessage( + const buzz::XmlElement& attachments) {} + +} // namespace remoting
diff --git a/remoting/client/host_experiment_sender.h b/remoting/client/host_experiment_sender.h new file mode 100644 index 0000000..d76944a --- /dev/null +++ b/remoting/client/host_experiment_sender.h
@@ -0,0 +1,35 @@ +// 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 REMOTING_CLIENT_HOST_EXPERIMENT_CONTROLLER_H_ +#define REMOTING_CLIENT_HOST_EXPERIMENT_CONTROLLER_H_ + +#include <memory> +#include <string> + +#include "remoting/protocol/session_plugin.h" +#include "third_party/libjingle_xmpp/xmllite/xmlelement.h" + +namespace remoting { + +// A SessionPlugin implementation to send host configuration to the host. +// Currently only WebApp sets the experiment configuration. +// This is a temporary solution until we have more permanent approach +// implemented, which should take host attributes into account. +class HostExperimentSender : public protocol::SessionPlugin { + public: + HostExperimentSender(const std::string& experiment_config); + + // protocol::SessionPlugin implementation. + std::unique_ptr<buzz::XmlElement> GetNextMessage() override; + + void OnIncomingMessage(const buzz::XmlElement& attachments) override; + private: + const std::string experiment_config_; + bool message_sent_ = false; +}; + +} // namespace remoting + +#endif // REMOTING_CLIENT_HOST_EXPERIMENT_CONTROLLER_H_
diff --git a/remoting/client/jni/remoting_jni_onload.cc b/remoting/client/jni/remoting_jni_onload.cc index 2140e4a..b4fa7c0 100644 --- a/remoting/client/jni/remoting_jni_onload.cc +++ b/remoting/client/jni/remoting_jni_onload.cc
@@ -23,18 +23,17 @@ }; bool RegisterJNI(JNIEnv* env) { - return base::android::RegisterNativeMethods(env, - kRemotingRegisteredMethods, arraysize(kRemotingRegisteredMethods)); + return base::android::RegisterNativeMethods( + env, kRemotingRegisteredMethods, arraysize(kRemotingRegisteredMethods)); } } // namespace JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { - std::vector<base::android::RegisterCallback> register_callbacks; - register_callbacks.push_back(base::Bind(&RegisterJNI)); - std::vector<base::android::InitCallback> init_callbacks; - if (!base::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks) || - !base::android::OnJNIOnLoadInit(init_callbacks)) { + base::android::InitVM(vm); + JNIEnv* env = base::android::AttachCurrentThread(); + if (!base::android::OnJNIOnLoadRegisterJNI(env) || !RegisterJNI(env) || + !base::android::OnJNIOnLoadInit()) { return -1; } return JNI_VERSION_1_4;
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc index 1fa13eb..4a339f5 100644 --- a/remoting/client/plugin/chromoting_instance.cc +++ b/remoting/client/plugin/chromoting_instance.cc
@@ -668,6 +668,10 @@ client_.reset(new ChromotingClient(&context_, this, video_renderer_.get(), audio_player_->GetWeakPtr())); + std::string host_experiment_config; + if (data.GetString("hostConfiguration", &host_experiment_config)) { + client_->set_host_experiment_config(host_experiment_config); + } // Setup the signal strategy. signal_strategy_.reset(new DelegatingSignalStrategy(
diff --git a/remoting/host/chromoting_host.cc b/remoting/host/chromoting_host.cc index 238b618c..0dd72d1 100644 --- a/remoting/host/chromoting_host.cc +++ b/remoting/host/chromoting_host.cc
@@ -256,15 +256,14 @@ video_encode_task_runner_, audio_task_runner_)); } - DesktopEnvironmentOptions options = desktop_environment_options_; - // TODO(zijiehe): Apply HostSessionOptions to options. // Create a ClientSession object. std::vector<HostExtension*> extension_ptrs; for (const auto& extension : extensions_) extension_ptrs.push_back(extension.get()); clients_.push_back(base::MakeUnique<ClientSession>( - this, std::move(connection), desktop_environment_factory_, options, - max_session_duration_, pairing_registry_, extension_ptrs)); + this, std::move(connection), desktop_environment_factory_, + desktop_environment_options_, max_session_duration_, pairing_registry_, + extension_ptrs)); } } // namespace remoting
diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc index f8df3b7..2edb8f9 100644 --- a/remoting/host/client_session.cc +++ b/remoting/host/client_session.cc
@@ -68,6 +68,7 @@ lossless_video_color_(!base::CommandLine::ForCurrentProcess()->HasSwitch( kDisableI444SwitchName)), weak_factory_(this) { + connection_->session()->AddPlugin(&host_experiment_session_plugin_); connection_->SetEventHandler(this); // Create a manager for the configured extensions, if any. @@ -241,10 +242,13 @@ // Notify EventHandler. event_handler_->OnSessionAuthenticated(this); + DesktopEnvironmentOptions options = desktop_environment_options_; + options.ApplyHostSessionOptions(HostSessionOptions( + host_experiment_session_plugin_.configuration())); // Create the desktop environment. Drop the connection if it could not be // created for any reason (for instance the curtain could not initialize). - desktop_environment_ = desktop_environment_factory_->Create( - weak_factory_.GetWeakPtr(), desktop_environment_options_); + desktop_environment_ = + desktop_environment_factory_->Create(weak_factory_.GetWeakPtr(), options); if (!desktop_environment_) { DisconnectSession(protocol::HOST_CONFIGURATION_ERROR); return;
diff --git a/remoting/host/client_session.h b/remoting/host/client_session.h index 15ea6df5..55e06d1 100644 --- a/remoting/host/client_session.h +++ b/remoting/host/client_session.h
@@ -19,6 +19,7 @@ #include "remoting/host/client_session_control.h" #include "remoting/host/client_session_details.h" #include "remoting/host/desktop_environment_options.h" +#include "remoting/host/host_experiment_session_plugin.h" #include "remoting/host/host_extension_session_manager.h" #include "remoting/host/remote_input_filter.h" #include "remoting/protocol/clipboard_echo_filter.h" @@ -245,6 +246,8 @@ scoped_refptr<protocol::InputEventTimestampsSource> event_timestamp_source_for_tests_; + HostExperimentSessionPlugin host_experiment_session_plugin_; + // Used to disable callbacks to |this| once DisconnectSession() has been // called. base::WeakPtrFactory<ClientSessionControl> weak_factory_;
diff --git a/remoting/host/client_session_unittest.cc b/remoting/host/client_session_unittest.cc index 920f3da..d2e830f 100644 --- a/remoting/host/client_session_unittest.cc +++ b/remoting/host/client_session_unittest.cc
@@ -11,6 +11,7 @@ #include <utility> #include <vector> +#include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/strings/string_split.h" @@ -28,6 +29,7 @@ #include "remoting/host/host_mock_objects.h" #include "remoting/protocol/fake_connection_to_client.h" #include "remoting/protocol/fake_desktop_capturer.h" +#include "remoting/protocol/fake_session.h" #include "remoting/protocol/protocol_mock_objects.h" #include "remoting/protocol/test_event_matchers.h" #include "testing/gmock/include/gmock/gmock-matchers.h" @@ -36,10 +38,10 @@ namespace remoting { +using protocol::FakeSession; using protocol::MockClientStub; using protocol::MockHostStub; using protocol::MockInputStub; -using protocol::MockSession; using protocol::MockVideoStub; using protocol::SessionConfig; using protocol::test::EqualsClipboardEvent; @@ -96,15 +98,18 @@ class ClientSessionTest : public testing::Test { public: - ClientSessionTest() : client_jid_("user@domain/rest-of-jid") {} + ClientSessionTest() = default; void SetUp() override; void TearDown() override; + protected: + // Creates the client session from a FakeSession instance. + void CreateClientSession(std::unique_ptr<protocol::FakeSession> session); + // Creates the client session. void CreateClientSession(); - protected: // Notifies the client session that the client connection has been // authenticated and channels have been connected. This effectively enables // the input pipe line and starts video capturing. @@ -113,10 +118,6 @@ // Fakes video size notification from the VideoStream. void NotifyVideoSize(); - // Creates expectations to send an extension message and to disconnect - // afterwards. - void SetSendMessageAndDisconnectExpectation(const std::string& message_type); - // Message loop that will process all ClientSession tasks. base::MessageLoop message_loop_; @@ -137,10 +138,6 @@ // ClientSession::EventHandler mock for use in tests. MockClientSessionEventHandler session_event_handler_; - // Storage for values to be returned by the protocol::Session mock. - std::unique_ptr<SessionConfig> session_config_; - const std::string client_jid_; - // Stubs returned to |client_session_| components by |connection_|. MockClientStub client_stub_; @@ -157,7 +154,6 @@ desktop_environment_factory_.reset( new FakeDesktopEnvironmentFactory(message_loop_.task_runner())); - session_config_ = SessionConfig::ForTest(); } void ClientSessionTest::TearDown() { @@ -173,11 +169,9 @@ run_loop_.Run(); } -void ClientSessionTest::CreateClientSession() { - // Mock protocol::Session APIs called directly by ClientSession. - std::unique_ptr<protocol::MockSession> session(new MockSession()); - EXPECT_CALL(*session, config()).WillRepeatedly(ReturnRef(*session_config_)); - EXPECT_CALL(*session, jid()).WillRepeatedly(ReturnRef(client_jid_)); +void ClientSessionTest::CreateClientSession( + std::unique_ptr<protocol::FakeSession> session) { + DCHECK(session); // Mock protocol::ConnectionToClient APIs called directly by ClientSession. // HostStub is not touched by ClientSession, so we can safely pass nullptr. @@ -193,6 +187,10 @@ base::TimeDelta(), nullptr, extensions_)); } +void ClientSessionTest::CreateClientSession() { + CreateClientSession(base::MakeUnique<protocol::FakeSession>()); +} + void ClientSessionTest::ConnectClientSession() { EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_)); EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_)); @@ -431,4 +429,62 @@ EXPECT_FALSE(extension3.was_instantiated()); } +TEST_F(ClientSessionTest, ForwardHostSessionOptions1) { + auto session = base::MakeUnique<protocol::FakeSession>(); + auto configuration = base::MakeUnique<buzz::XmlElement>( + buzz::QName(kChromotingXmlNamespace, "host-configuration")); + configuration->SetBodyText("Detect-Updated-Region:true"); + session->SetAttachment(0, std::move(configuration)); + CreateClientSession(std::move(session)); + ConnectClientSession(); + ASSERT_TRUE(desktop_environment_factory_->last_desktop_environment() + ->options() + .desktop_capture_options() + ->detect_updated_region()); +} + +TEST_F(ClientSessionTest, ForwardHostSessionOptions2) { + auto session = base::MakeUnique<protocol::FakeSession>(); + auto configuration = base::MakeUnique<buzz::XmlElement>( + buzz::QName(kChromotingXmlNamespace, "host-configuration")); + configuration->SetBodyText("Detect-Updated-Region:false"); + session->SetAttachment(0, std::move(configuration)); + CreateClientSession(std::move(session)); + ConnectClientSession(); + ASSERT_FALSE(desktop_environment_factory_->last_desktop_environment() + ->options() + .desktop_capture_options() + ->detect_updated_region()); +} + +#if defined(OS_WIN) +TEST_F(ClientSessionTest, ForwardDirectXHostSessionOptions1) { + auto session = base::MakeUnique<protocol::FakeSession>(); + auto configuration = base::MakeUnique<buzz::XmlElement>( + buzz::QName(kChromotingXmlNamespace, "host-configuration")); + configuration->SetBodyText("DirectX-Capturer:true"); + session->SetAttachment(0, std::move(configuration)); + CreateClientSession(std::move(session)); + ConnectClientSession(); + ASSERT_TRUE(desktop_environment_factory_->last_desktop_environment() + ->options() + .desktop_capture_options() + ->allow_directx_capturer()); +} + +TEST_F(ClientSessionTest, ForwardDirectXHostSessionOptions2) { + auto session = base::MakeUnique<protocol::FakeSession>(); + auto configuration = base::MakeUnique<buzz::XmlElement>( + buzz::QName(kChromotingXmlNamespace, "host-configuration")); + configuration->SetBodyText("DirectX-Capturer:false"); + session->SetAttachment(0, std::move(configuration)); + CreateClientSession(std::move(session)); + ConnectClientSession(); + ASSERT_FALSE(desktop_environment_factory_->last_desktop_environment() + ->options() + .desktop_capture_options() + ->allow_directx_capturer()); +} +#endif + } // namespace remoting
diff --git a/remoting/host/desktop_environment_options.cc b/remoting/host/desktop_environment_options.cc index ec1995e..0e15351c 100644 --- a/remoting/host/desktop_environment_options.cc +++ b/remoting/host/desktop_environment_options.cc
@@ -4,8 +4,11 @@ #include "remoting/host/desktop_environment_options.h" +#include <string> #include <utility> +#include "base/optional.h" + namespace remoting { using DesktopCaptureOptions = webrtc::DesktopCaptureOptions; @@ -68,4 +71,23 @@ enable_user_interface_ = enabled; } +void DesktopEnvironmentOptions::ApplyHostSessionOptions( + const HostSessionOptions& options) { +#if defined(OS_WIN) + base::Optional<std::string> directx_capturer = + options.Get("DirectX-Capturer"); + if (directx_capturer) { + desktop_capture_options_.set_allow_directx_capturer( + *directx_capturer == "true"); + } +#endif + // This field is for test purpose. Usually it should not be set to false. + base::Optional<std::string> detect_updated_region = + options.Get("Detect-Updated-Region"); + if (detect_updated_region) { + desktop_capture_options_.set_detect_updated_region( + *detect_updated_region == "true"); + } +} + } // namespace remoting
diff --git a/remoting/host/desktop_environment_options.h b/remoting/host/desktop_environment_options.h index 31044c6..15cacfa8 100644 --- a/remoting/host/desktop_environment_options.h +++ b/remoting/host/desktop_environment_options.h
@@ -8,12 +8,9 @@ #include <memory> #include "base/memory/weak_ptr.h" +#include "remoting/host/host_session_options.h" #include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h" -namespace webrtc { -class DesktopCaptureOptions; -} // namespace webrtc - namespace remoting { // A container of options a DesktopEnvironment or its derived classes need to @@ -42,6 +39,9 @@ const webrtc::DesktopCaptureOptions* desktop_capture_options() const; webrtc::DesktopCaptureOptions* desktop_capture_options(); + // Reads configurations from a HostSessionOptions instance. + void ApplyHostSessionOptions(const HostSessionOptions& options); + private: // Sets default values for default constructor and CreateDefault() function. void Initialize();
diff --git a/remoting/host/fake_desktop_environment.cc b/remoting/host/fake_desktop_environment.cc index 9b97de19..6597f96 100644 --- a/remoting/host/fake_desktop_environment.cc +++ b/remoting/host/fake_desktop_environment.cc
@@ -55,8 +55,9 @@ } FakeDesktopEnvironment::FakeDesktopEnvironment( - scoped_refptr<base::SingleThreadTaskRunner> capture_thread) - : capture_thread_(std::move(capture_thread)) {} + scoped_refptr<base::SingleThreadTaskRunner> capture_thread, + const DesktopEnvironmentOptions& options) + : capture_thread_(std::move(capture_thread)), options_(options) {} FakeDesktopEnvironment::~FakeDesktopEnvironment() = default; @@ -103,6 +104,10 @@ return UINT32_MAX; } +const DesktopEnvironmentOptions& FakeDesktopEnvironment::options() const { + return options_; +} + FakeDesktopEnvironmentFactory::FakeDesktopEnvironmentFactory( scoped_refptr<base::SingleThreadTaskRunner> capture_thread) : capture_thread_(std::move(capture_thread)) {} @@ -114,7 +119,7 @@ base::WeakPtr<ClientSessionControl> client_session_control, const DesktopEnvironmentOptions& options) { std::unique_ptr<FakeDesktopEnvironment> result( - new FakeDesktopEnvironment(capture_thread_)); + new FakeDesktopEnvironment(capture_thread_, options)); result->set_frame_generator(frame_generator_); last_desktop_environment_ = result->AsWeakPtr(); return std::move(result);
diff --git a/remoting/host/fake_desktop_environment.h b/remoting/host/fake_desktop_environment.h index 956ca505..116678e 100644 --- a/remoting/host/fake_desktop_environment.h +++ b/remoting/host/fake_desktop_environment.h
@@ -13,6 +13,7 @@ #include "base/macros.h" #include "base/single_thread_task_runner.h" #include "remoting/host/desktop_environment.h" +#include "remoting/host/desktop_environment_options.h" #include "remoting/host/fake_mouse_cursor_monitor.h" #include "remoting/host/input_injector.h" #include "remoting/host/screen_controls.h" @@ -73,7 +74,8 @@ public base::SupportsWeakPtr<FakeDesktopEnvironment> { public: explicit FakeDesktopEnvironment( - scoped_refptr<base::SingleThreadTaskRunner> capture_thread); + scoped_refptr<base::SingleThreadTaskRunner> capture_thread, + const DesktopEnvironmentOptions& options); ~FakeDesktopEnvironment() override; // Sets frame generator to be used for protocol::FakeDesktopCapturer created @@ -83,6 +85,8 @@ frame_generator_ = frame_generator; } + const DesktopEnvironmentOptions& options() const; + // DesktopEnvironment implementation. std::unique_ptr<AudioCapturer> CreateAudioCapturer() override; std::unique_ptr<InputInjector> CreateInputInjector() override; @@ -104,6 +108,8 @@ base::WeakPtr<FakeInputInjector> last_input_injector_; + const DesktopEnvironmentOptions options_; + DISALLOW_COPY_AND_ASSIGN(FakeDesktopEnvironment); };
diff --git a/remoting/host/host_session_options.cc b/remoting/host/host_session_options.cc index 2424b88..8511f27 100644 --- a/remoting/host/host_session_options.cc +++ b/remoting/host/host_session_options.cc
@@ -11,7 +11,6 @@ #include "base/strings/string_util.h" namespace remoting { -namespace protocol { namespace { @@ -35,6 +34,10 @@ HostSessionOptions::HostSessionOptions() = default; HostSessionOptions::~HostSessionOptions() = default; +HostSessionOptions::HostSessionOptions(const std::string& parameter) { + Import(parameter); +} + void HostSessionOptions::Append(const std::string& key, const std::string& value) { DCHECK(KeyIsValid(key)); @@ -80,5 +83,4 @@ } } -} // namespace protocol } // namespace remoting
diff --git a/remoting/host/host_session_options.h b/remoting/host/host_session_options.h index e302b4b..158a400 100644 --- a/remoting/host/host_session_options.h +++ b/remoting/host/host_session_options.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef REMOTING_PROTOCOL_HOST_SESSION_OPTIONS_H_ -#define REMOTING_PROTOCOL_HOST_SESSION_OPTIONS_H_ +#ifndef REMOTING_HOST_HOST_SESSION_OPTIONS_H_ +#define REMOTING_HOST_HOST_SESSION_OPTIONS_H_ #include <map> #include <string> @@ -12,7 +12,6 @@ #include "base/optional.h" namespace remoting { -namespace protocol { // Session based host options sending from client. This class parses and stores // session configuration from client side to control the behavior of other host @@ -22,6 +21,8 @@ HostSessionOptions(); ~HostSessionOptions(); + HostSessionOptions(const std::string& parameter); + // Appends one key-value pair into current instance. void Append(const std::string& key, const std::string& value); @@ -46,7 +47,6 @@ DISALLOW_COPY_AND_ASSIGN(HostSessionOptions); }; -} // namespace protocol } // namespace remoting -#endif // REMOTING_PROTOCOL_HOST_SESSION_OPTIONS_H_ +#endif // REMOTING_HOST_HOST_SESSION_OPTIONS_H_
diff --git a/remoting/host/host_session_options_unittest.cc b/remoting/host/host_session_options_unittest.cc index f994934..1c7195b 100644 --- a/remoting/host/host_session_options_unittest.cc +++ b/remoting/host/host_session_options_unittest.cc
@@ -7,7 +7,6 @@ #include "testing/gtest/include/gtest/gtest.h" namespace remoting { -namespace protocol { TEST(HostSessionOptionsTest, ShouldBeAbleToAppendOptions) { HostSessionOptions options; @@ -52,5 +51,4 @@ ASSERT_EQ(options.Export(), other.Export()); } -} // namespace protocol } // namespace remoting
diff --git a/remoting/host/security_key/fake_security_key_ipc_client.cc b/remoting/host/security_key/fake_security_key_ipc_client.cc index 70eb8bc..47f0c531 100644 --- a/remoting/host/security_key/fake_security_key_ipc_client.cc +++ b/remoting/host/security_key/fake_security_key_ipc_client.cc
@@ -109,7 +109,12 @@ void FakeSecurityKeyIpcClient::OnChannelConnected(int32_t peer_pid) { ipc_channel_connected_ = true; - channel_event_callback_.Run(); + + // We don't always want to fire this event as only a subset of tests care + // about the channel being connected. Tests that do care can register for it. + if (on_channel_connected_callback_) { + on_channel_connected_callback_.Run(); + } } void FakeSecurityKeyIpcClient::OnChannelError() {
diff --git a/remoting/host/security_key/fake_security_key_ipc_client.h b/remoting/host/security_key/fake_security_key_ipc_client.h index b3b9523..5e314f4 100644 --- a/remoting/host/security_key/fake_security_key_ipc_client.h +++ b/remoting/host/security_key/fake_security_key_ipc_client.h
@@ -75,6 +75,10 @@ security_key_response_payload_ = response_payload; } + void set_on_channel_connected_callback(const base::Closure& callback) { + on_channel_connected_callback_ = callback; + } + private: // IPC::Listener implementation. bool OnMessageReceived(const IPC::Message& message) override; @@ -93,6 +97,9 @@ // Called when a change in the IPC channel state has occurred. base::Closure channel_event_callback_; + // Called when the IPC Channel is connected. + base::Closure on_channel_connected_callback_; + // Used for sending/receiving security key messages between processes. std::unique_ptr<IPC::Channel> client_channel_;
diff --git a/remoting/host/security_key/security_key_auth_handler_win_unittest.cc b/remoting/host/security_key/security_key_auth_handler_win_unittest.cc index 58ad21c..894d5a3 100644 --- a/remoting/host/security_key/security_key_auth_handler_win_unittest.cc +++ b/remoting/host/security_key/security_key_auth_handler_win_unittest.cc
@@ -17,7 +17,6 @@ #include "ipc/ipc_listener.h" #include "ipc/ipc_message.h" #include "ipc/ipc_message_macros.h" -#include "mojo/edk/embedder/scoped_ipc_support.h" #include "remoting/host/host_mock_objects.h" #include "remoting/host/security_key/fake_security_key_ipc_client.h" #include "remoting/host/security_key/fake_security_key_ipc_server.h" @@ -88,8 +87,6 @@ // IPC tests require a valid MessageLoop to run. base::MessageLoopForIO message_loop_; - mojo::edk::ScopedIPCSupport ipc_support_; - // Used to allow |message_loop_| to run during tests. The instance is reset // after each stage of the tests has been completed. std::unique_ptr<base::RunLoop> run_loop_; @@ -116,9 +113,7 @@ }; SecurityKeyAuthHandlerWinTest::SecurityKeyAuthHandlerWinTest() - : ipc_support_(message_loop_.task_runner(), - mojo::edk::ScopedIPCSupport::ShutdownPolicy::FAST), - run_loop_(new base::RunLoop()) { + : run_loop_(new base::RunLoop()) { auth_handler_ = remoting::SecurityKeyAuthHandler::Create( &mock_client_session_details_, base::Bind(&SecurityKeyAuthHandlerWinTest::SendMessageToClient, @@ -164,9 +159,19 @@ auth_handler_->GetActiveConnectionCountForTest() + 1; ASSERT_FALSE(auth_handler_->IsValidConnectionId(expected_connection_id)); + fake_ipc_client->set_on_channel_connected_callback( + base::Bind(&SecurityKeyAuthHandlerWinTest::OperationComplete, + base::Unretained(this))); ASSERT_TRUE(fake_ipc_client->ConnectViaIpc(channel_handle)); WaitForOperationComplete(); + // Retrieve the IPC server instance created when the client connected. + base::WeakPtr<FakeSecurityKeyIpcServer> fake_ipc_server = + ipc_server_factory_.GetIpcServerObject(expected_connection_id); + ASSERT_TRUE(fake_ipc_server.get()); + fake_ipc_server->SendConnectionReadyMessage(); + WaitForOperationComplete(); + // Verify the internal state of the SecurityKeyAuthHandler is correct. ASSERT_TRUE(auth_handler_->IsValidConnectionId(expected_connection_id)); ASSERT_EQ(expected_connection_count, @@ -248,7 +253,6 @@ TEST_F(SecurityKeyAuthHandlerWinTest, HandleSingleSecurityKeyRequest) { mojo::edk::NamedPlatformHandle channel_handle(GetUniqueTestChannelHandle()); CreateSecurityKeyConnection(channel_handle); - ASSERT_FALSE(auth_handler_->IsValidConnectionId(kConnectionId1)); // Create a fake client and connect to the IPC server channel.
diff --git a/remoting/host/security_key/security_key_ipc_client_unittest.cc b/remoting/host/security_key/security_key_ipc_client_unittest.cc index ad9e5f3..1fadf54d 100644 --- a/remoting/host/security_key/security_key_ipc_client_unittest.cc +++ b/remoting/host/security_key/security_key_ipc_client_unittest.cc
@@ -13,7 +13,6 @@ #include "base/run_loop.h" #include "ipc/ipc_channel.h" #include "mojo/edk/embedder/named_platform_handle_utils.h" -#include "mojo/edk/embedder/scoped_ipc_support.h" #include "remoting/host/security_key/fake_security_key_ipc_server.h" #include "remoting/host/security_key/security_key_ipc_constants.h" #include "testing/gtest/include/gtest/gtest.h" @@ -57,6 +56,9 @@ // Waits until the current |run_loop_| instance is signaled, then resets it. void WaitForOperationComplete(); + // Waits until all tasks have been run on the current message loop. + void RunPendingTasks(); + // Sets up an active IPC connection between |security_key_ipc_client_| // and |fake_ipc_server_|. |expect_connected| defines whether the operation // is result in a usable IPC connection. |expect_error| defines whether the @@ -74,8 +76,6 @@ // IPC tests require a valid MessageLoop to run. base::MessageLoopForIO message_loop_; - mojo::edk::ScopedIPCSupport ipc_support_; - // Used to allow |message_loop_| to run during tests. The instance is reset // after each stage of the tests has been completed. std::unique_ptr<base::RunLoop> run_loop_; @@ -110,9 +110,7 @@ }; SecurityKeyIpcClientTest::SecurityKeyIpcClientTest() - : ipc_support_(message_loop_.task_runner(), - mojo::edk::ScopedIPCSupport::ShutdownPolicy::FAST), - run_loop_(new base::RunLoop()), + : run_loop_(new base::RunLoop()), fake_ipc_server_( kTestConnectionId, /*client_session_details=*/nullptr, @@ -161,6 +159,11 @@ run_loop_.reset(new base::RunLoop()); } +void SecurityKeyIpcClientTest::RunPendingTasks() { + // Run until there are no pending work items in the queue. + base::RunLoop().RunUntilIdle(); +} + void SecurityKeyIpcClientTest::SendMessageToClient(int connection_id, const std::string& data) { last_connection_id_received_ = connection_id; @@ -200,6 +203,8 @@ base::Bind(&SecurityKeyIpcClientTest::OperationComplete, base::Unretained(this), /*failed=*/true)); WaitForOperationComplete(); + RunPendingTasks(); + ASSERT_EQ(expect_connected, connection_established_); ASSERT_EQ(expect_error, operation_failed_); }
diff --git a/remoting/host/security_key/security_key_ipc_server_unittest.cc b/remoting/host/security_key/security_key_ipc_server_unittest.cc index 075b27e..227ea1f 100644 --- a/remoting/host/security_key/security_key_ipc_server_unittest.cc +++ b/remoting/host/security_key/security_key_ipc_server_unittest.cc
@@ -16,7 +16,6 @@ #include "ipc/ipc_channel.h" #include "mojo/edk/embedder/embedder.h" #include "mojo/edk/embedder/named_platform_handle_utils.h" -#include "mojo/edk/embedder/scoped_ipc_support.h" #include "remoting/host/client_session_details.h" #include "remoting/host/security_key/fake_security_key_ipc_client.h" #include "remoting/host/security_key/security_key_ipc_constants.h" @@ -45,6 +44,9 @@ void SendRequestToClient(int connection_id, const std::string& data); protected: + // testing::Test interface. + void TearDown() override; + // Returns a unique IPC channel name which prevents conflicts when running // tests concurrently. std::string GetUniqueTestChannelName(); @@ -52,6 +54,9 @@ // Waits until the current |run_loop_| instance is signaled, then resets it. void WaitForOperationComplete(); + // Waits until all tasks have been run on the current message loop. + void RunPendingTasks(); + // ClientSessionControl overrides: ClientSessionControl* session_control() override { return nullptr; } uint32_t desktop_session_id() const override { return peer_session_id_; } @@ -59,8 +64,6 @@ // IPC tests require a valid MessageLoop to run. base::MessageLoopForIO message_loop_; - mojo::edk::ScopedIPCSupport ipc_support_; - // Used to allow |message_loop_| to run during tests. The instance is reset // after each stage of the tests has been completed. std::unique_ptr<base::RunLoop> run_loop_; @@ -82,9 +85,7 @@ }; SecurityKeyIpcServerTest::SecurityKeyIpcServerTest() - : ipc_support_(message_loop_.task_runner(), - mojo::edk::ScopedIPCSupport::ShutdownPolicy::FAST), - run_loop_(new base::RunLoop()) { + : run_loop_(new base::RunLoop()) { #if defined(OS_WIN) EXPECT_TRUE(ProcessIdToSessionId( GetCurrentProcessId(), reinterpret_cast<DWORD*>(&peer_session_id_))); @@ -111,6 +112,15 @@ run_loop_.reset(new base::RunLoop()); } +void SecurityKeyIpcServerTest::RunPendingTasks() { + // Run until there are no pending work items in the queue. + base::RunLoop().RunUntilIdle(); +} + +void SecurityKeyIpcServerTest::TearDown() { + RunPendingTasks(); +} + void SecurityKeyIpcServerTest::SendRequestToClient(int connection_id, const std::string& data) { last_connection_id_received_ = connection_id; @@ -135,9 +145,9 @@ ASSERT_TRUE(fake_ipc_client.ConnectViaIpc(channel_handle)); WaitForOperationComplete(); + ASSERT_TRUE(fake_ipc_client.ipc_channel_connected()); ASSERT_FALSE(fake_ipc_client.invalid_session_error()); ASSERT_TRUE(fake_ipc_client.connection_ready()); - ASSERT_TRUE(fake_ipc_client.ipc_channel_connected()); // Send a request from the IPC client to the IPC server. std::string request_data("Blergh!"); @@ -489,16 +499,15 @@ security_key_ipc_server_->CreateChannel(channel_handle, request_timeout)); // Create a fake client and attempt to connect to the IPC server channel. - FakeSecurityKeyIpcClient fake_ipc_client(base::Bind( - &SecurityKeyIpcServerTest::OperationComplete, base::Unretained(this))); + FakeSecurityKeyIpcClient fake_ipc_client(base::Bind(&base::DoNothing)); ASSERT_TRUE(fake_ipc_client.ConnectViaIpc(channel_handle)); WaitForOperationComplete(); - WaitForOperationComplete(); - WaitForOperationComplete(); // Verify the connection failed. ASSERT_TRUE(fake_ipc_client.invalid_session_error()); ASSERT_FALSE(fake_ipc_client.connection_ready()); + + RunPendingTasks(); ASSERT_FALSE(fake_ipc_client.ipc_channel_connected()); } #endif // defined(OS_WIN)
diff --git a/remoting/protocol/fake_session.cc b/remoting/protocol/fake_session.cc index 56cbd51..0ed08da 100644 --- a/remoting/protocol/fake_session.cc +++ b/remoting/protocol/fake_session.cc
@@ -6,6 +6,7 @@ #include "base/location.h" #include "base/logging.h" +#include "base/memory/ptr_util.h" #include "base/threading/thread_task_runner_handle.h" #include "remoting/protocol/fake_authenticator.h" #include "remoting/protocol/session_plugin.h" @@ -104,9 +105,24 @@ transport_->ProcessTransportInfo(transport_info.get()); } -// TODO(zijiehe): Supports SessionPlugin in FakeSession. void FakeSession::AddPlugin(SessionPlugin* plugin) { - NOTIMPLEMENTED(); + DCHECK(plugin); + for (const auto& message : attachments_) { + if (message) { + JingleMessage jingle_message; + jingle_message.AddAttachment( + base::MakeUnique<buzz::XmlElement>(*message)); + plugin->OnIncomingMessage(*(jingle_message.attachments)); + } + } +} + +void FakeSession::SetAttachment(size_t round, + std::unique_ptr<buzz::XmlElement> attachment) { + while (attachments_.size() <= round) { + attachments_.emplace_back(); + } + attachments_[round] = std::move(attachment); } } // namespace protocol
diff --git a/remoting/protocol/fake_session.h b/remoting/protocol/fake_session.h index 7d31c9c..b0487c86 100644 --- a/remoting/protocol/fake_session.h +++ b/remoting/protocol/fake_session.h
@@ -14,6 +14,7 @@ #include "base/memory/weak_ptr.h" #include "base/time/time.h" #include "remoting/protocol/fake_stream_socket.h" +#include "remoting/protocol/jingle_messages.h" #include "remoting/protocol/session.h" #include "remoting/protocol/transport.h" @@ -40,6 +41,11 @@ signaling_delay_ = signaling_delay; } + // Adds an |attachment| to |round|, which will be sent to plugins added by + // AddPlugin() function. + void SetAttachment(size_t round, + std::unique_ptr<buzz::XmlElement> attachment); + // Session interface. void SetEventHandler(EventHandler* event_handler) override; ErrorCode error() override; @@ -70,6 +76,8 @@ base::WeakPtr<FakeSession> peer_; base::TimeDelta signaling_delay_; + std::vector<std::unique_ptr<buzz::XmlElement>> attachments_; + base::WeakPtrFactory<FakeSession> weak_factory_; DISALLOW_COPY_AND_ASSIGN(FakeSession);
diff --git a/remoting/webapp/base/js/client_plugin_impl.js b/remoting/webapp/base/js/client_plugin_impl.js index da327d8..ae72b7e 100644 --- a/remoting/webapp/base/js/client_plugin_impl.js +++ b/remoting/webapp/base/js/client_plugin_impl.js
@@ -16,6 +16,14 @@ /** @suppress {duplicate} */ var remoting = remoting || {}; +/** + * @type {string} The host configuration which will be sent to host to control + * its experiment behavior. We do not have a short term plan to support host + * experiment in WebApp, so this variable can only be controlled by + * developer console, and it's for debugging purpose only. + */ +remoting.hostConfiguration = ''; + /** @constructor */ remoting.ClientPluginMessage = function() { /** @type {string} */ @@ -456,7 +464,8 @@ clientPairingId: credentialsProvider.getPairingInfo().clientId, clientPairedSecret: credentialsProvider.getPairingInfo().sharedSecret, keyFilter: keyFilter, - experiments: experiments.join(" ") + experiments: experiments.join(" "), + hostConfiguration: remoting.hostConfiguration } })); };
diff --git a/sandbox/win/OWNERS b/sandbox/win/OWNERS index 54a76c1..4a33d0177 100644 --- a/sandbox/win/OWNERS +++ b/sandbox/win/OWNERS
@@ -1,4 +1,5 @@ cpu@chromium.org forshaw@chromium.org jschuh@chromium.org +pennymac@chromium.org wfh@chromium.org
diff --git a/services/catalog/entry.h b/services/catalog/entry.h index b54e0576..3e43592 100644 --- a/services/catalog/entry.h +++ b/services/catalog/entry.h
@@ -16,6 +16,7 @@ #include "services/service_manager/public/interfaces/resolver.mojom.h" namespace base { +class DictionaryValue; class Value; }
diff --git a/services/service_manager/background/tests/background_service_manager_unittest.cc b/services/service_manager/background/tests/background_service_manager_unittest.cc index 02c4df9d..e939e0e 100644 --- a/services/service_manager/background/tests/background_service_manager_unittest.cc +++ b/services/service_manager/background/tests/background_service_manager_unittest.cc
@@ -8,6 +8,7 @@ #include "base/memory/ptr_util.h" #include "base/run_loop.h" +#include "base/values.h" #include "services/service_manager/background/tests/test.mojom.h" #include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/service.h"
diff --git a/services/service_manager/public/cpp/lib/service_runner.cc b/services/service_manager/public/cpp/lib/service_runner.cc index 99e1130..374a948 100644 --- a/services/service_manager/public/cpp/lib/service_runner.cc +++ b/services/service_manager/public/cpp/lib/service_runner.cc
@@ -59,13 +59,6 @@ base::RunLoop run_loop; context_->SetConnectionLostClosure(run_loop.QuitClosure()); run_loop.Run(); - // It's very common for the service to cache the app and terminate on - // errors. If we don't delete the service before the app we run the risk of - // the service having a stale reference to the app and trying to use it. - // Note that we destruct the message loop first because that might trigger - // connection error handlers and they might access objects created by the - // service. - loop.reset(); context_.reset(); } return MOJO_RESULT_OK;
diff --git a/services/service_manager/public/cpp/lib/service_test.cc b/services/service_manager/public/cpp/lib/service_test.cc index 23ee61ea..0c938f2b 100644 --- a/services/service_manager/public/cpp/lib/service_test.cc +++ b/services/service_manager/public/cpp/lib/service_test.cc
@@ -8,6 +8,7 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/threading/thread.h" +#include "base/values.h" #include "mojo/edk/embedder/embedder.h" #include "mojo/edk/embedder/scoped_ipc_support.h" #include "services/service_manager/background/background_service_manager.h"
diff --git a/services/service_manager/public/cpp/test/run_all_service_tests.cc b/services/service_manager/public/cpp/test/run_all_service_tests.cc index 8d02f3f..449d8ebc 100644 --- a/services/service_manager/public/cpp/test/run_all_service_tests.cc +++ b/services/service_manager/public/cpp/test/run_all_service_tests.cc
@@ -6,6 +6,7 @@ #include "base/test/launcher/unit_test_launcher.h" #include "base/test/test_suite.h" #include "base/threading/thread.h" +#include "base/values.h" #include "mojo/edk/embedder/embedder.h" #include "mojo/edk/embedder/scoped_ipc_support.h" #include "services/catalog/catalog.h"
diff --git a/services/ui/test_wm/test_wm.cc b/services/ui/test_wm/test_wm.cc index d9e2c9e..a0c75db 100644 --- a/services/ui/test_wm/test_wm.cc +++ b/services/ui/test_wm/test_wm.cc
@@ -39,6 +39,8 @@ TestWM() {} ~TestWM() override { + default_capture_client_.reset(); + // WindowTreeHost uses state from WindowTreeClient, so destroy it first. window_tree_host_.reset(); @@ -147,6 +149,7 @@ void OnWmDisplayRemoved(aura::WindowTreeHostMus* window_tree_host) override { DCHECK_EQ(window_tree_host, window_tree_host_.get()); root_ = nullptr; + default_capture_client_.reset(); window_tree_host_.reset(); } void OnWmDisplayModified(const display::Display& display) override {}
diff --git a/services/ui/ws/cursor_unittest.cc b/services/ui/ws/cursor_unittest.cc index bfd4008..c206118 100644 --- a/services/ui/ws/cursor_unittest.cc +++ b/services/ui/ws/cursor_unittest.cc
@@ -95,8 +95,8 @@ WindowManagerDisplayRoot* active_display_root = display->GetActiveWindowManagerDisplayRoot(); ASSERT_TRUE(active_display_root); - static_cast<PlatformDisplayDelegate*>(display)->OnEvent(ui::PointerEvent( - ui::MouseEvent(ui::ET_MOUSE_MOVED, p, p, base::TimeTicks(), 0, 0))); + static_cast<PlatformDisplayDelegate*>(display)->OnEvent(PointerEvent( + MouseEvent(ET_MOUSE_MOVED, p, p, base::TimeTicks(), 0, 0))); WindowManagerState* wms = active_display_root->window_manager_state(); wms->OnEventAck(wms->window_tree(), mojom::EventResult::HANDLED); } @@ -110,6 +110,7 @@ TEST_F(CursorTest, ChangeByMouseMove) { ServerWindow* win = BuildServerWindow(); win->SetPredefinedCursor(mojom::Cursor::IBEAM); + win->parent()->SetPredefinedCursor(mojom::Cursor::CELL); EXPECT_EQ(mojom::Cursor::IBEAM, win->cursor()); win->SetNonClientCursor(mojom::Cursor::EAST_RESIZE); EXPECT_EQ(mojom::Cursor::EAST_RESIZE, win->non_client_cursor()); @@ -118,13 +119,14 @@ MoveCursorTo(gfx::Point(15, 15)); EXPECT_EQ(mojom::Cursor::EAST_RESIZE, cursor()); - // Client area + // Client area, which comes from win->parent(). MoveCursorTo(gfx::Point(25, 25)); - EXPECT_EQ(mojom::Cursor::IBEAM, cursor()); + EXPECT_EQ(mojom::Cursor::CELL, cursor()); } TEST_F(CursorTest, ChangeByClientAreaChange) { ServerWindow* win = BuildServerWindow(); + win->parent()->SetPredefinedCursor(mojom::Cursor::CROSS); win->SetPredefinedCursor(mojom::Cursor::IBEAM); EXPECT_EQ(mojom::Cursor::IBEAM, mojom::Cursor(win->cursor())); win->SetNonClientCursor(mojom::Cursor::EAST_RESIZE); @@ -134,9 +136,10 @@ MoveCursorTo(gfx::Point(15, 15)); EXPECT_EQ(mojom::Cursor::EAST_RESIZE, cursor()); - // Changing the client area should cause a change. + // Changing the client area should cause a change. The cursor for the client + // area comes from root ancestor, which is win->parent(). win->SetClientArea(gfx::Insets(1, 1), std::vector<gfx::Rect>()); - EXPECT_EQ(mojom::Cursor::IBEAM, cursor()); + EXPECT_EQ(mojom::Cursor::CROSS, cursor()); } TEST_F(CursorTest, NonClientCursorChange) { @@ -169,6 +172,7 @@ TEST_F(CursorTest, NonClientToClientByBoundsChange) { ServerWindow* win = BuildServerWindow(); + win->parent()->SetPredefinedCursor(mojom::Cursor::COPY); win->SetPredefinedCursor(mojom::Cursor::IBEAM); EXPECT_EQ(mojom::Cursor::IBEAM, win->cursor()); win->SetNonClientCursor(mojom::Cursor::EAST_RESIZE); @@ -179,7 +183,7 @@ EXPECT_EQ(mojom::Cursor::EAST_RESIZE, cursor()); win->SetBounds(gfx::Rect(0, 0, 30, 30)); - EXPECT_EQ(mojom::Cursor::IBEAM, cursor()); + EXPECT_EQ(mojom::Cursor::COPY, cursor()); } } // namespace test
diff --git a/services/ui/ws/drag_controller.h b/services/ui/ws/drag_controller.h index 0057480..cb40282 100644 --- a/services/ui/ws/drag_controller.h +++ b/services/ui/ws/drag_controller.h
@@ -14,7 +14,13 @@ #include "services/ui/ws/ids.h" #include "services/ui/ws/server_window_observer.h" +namespace gfx { +class Point; +} + namespace ui { +class PointerEvent; + namespace ws { namespace test {
diff --git a/services/ui/ws/event_dispatcher.cc b/services/ui/ws/event_dispatcher.cc index c592a64..80822401 100644 --- a/services/ui/ws/event_dispatcher.cc +++ b/services/ui/ws/event_dispatcher.cc
@@ -92,9 +92,11 @@ if (!mouse_cursor_source_window_) return ui::mojom::Cursor::POINTER; - return mouse_cursor_in_non_client_area_ - ? mouse_cursor_source_window_->non_client_cursor() - : mouse_cursor_source_window_->cursor(); + if (mouse_cursor_in_non_client_area_) + return mouse_cursor_source_window_->non_client_cursor(); + + const ServerWindow* window = GetWindowForMouseCursor(); + return window ? window->cursor() : ui::mojom::Cursor::POINTER; } bool EventDispatcher::SetCaptureWindow(ServerWindow* window, @@ -197,6 +199,22 @@ SetCaptureWindow(nullptr, kInvalidClientId); } +const ServerWindow* EventDispatcher::GetWindowForMouseCursor() const { + if (mouse_cursor_in_non_client_area_ || !mouse_cursor_source_window_) + return mouse_cursor_source_window_; + + // Return the ancestor (starting at |mouse_cursor_source_window_|) whose + // client id differs. In other words, return the first window ancestor that is + // an embed root. This is done to match the behavior of aura, which sets the + // cursor on the root. + const ClientSpecificId target_client_id = delegate_->GetEventTargetClientId( + mouse_cursor_source_window_, mouse_cursor_in_non_client_area_); + const ServerWindow* window = mouse_cursor_source_window_; + while (window && window->id().client_id == target_client_id) + window = window->parent(); + return window; +} + void EventDispatcher::UpdateNonClientAreaForCurrentWindow() { if (mouse_cursor_source_window_) { DeepestWindow deepest_window =
diff --git a/services/ui/ws/event_dispatcher.h b/services/ui/ws/event_dispatcher.h index cd05854c..7e1341e2 100644 --- a/services/ui/ws/event_dispatcher.h +++ b/services/ui/ws/event_dispatcher.h
@@ -24,6 +24,7 @@ class Event; class KeyEvent; class LocatedEvent; +class PointerEvent; namespace ws { @@ -114,6 +115,11 @@ return mouse_cursor_source_window_; } + // Returns the window the mouse cursor is taken from. This does not take + // into account drags. In other words if there is a drag on going the mouse + // comes comes from a different window. + const ServerWindow* GetWindowForMouseCursor() const; + // If the mouse cursor is still over |mouse_cursor_source_window_|, updates // whether we are in the non-client area. Used when // |mouse_cursor_source_window_| has changed its properties.
diff --git a/services/ui/ws/event_dispatcher_delegate.h b/services/ui/ws/event_dispatcher_delegate.h index eb0c51a..69b7a1b 100644 --- a/services/ui/ws/event_dispatcher_delegate.h +++ b/services/ui/ws/event_dispatcher_delegate.h
@@ -14,10 +14,9 @@ } namespace ui { -class Event; -} -namespace ui { +class Event; + namespace ws { class Accelerator;
diff --git a/services/ui/ws/frame_generator.cc b/services/ui/ws/frame_generator.cc index 524a497..4a7809f 100644 --- a/services/ui/ws/frame_generator.cc +++ b/services/ui/ws/frame_generator.cc
@@ -26,8 +26,7 @@ ServerWindow* root_window) : delegate_(delegate), root_window_(root_window), - binding_(this), - weak_factory_(this) { + binding_(this) { DCHECK(delegate_); } @@ -40,9 +39,6 @@ } FrameGenerator::~FrameGenerator() { - // Invalidate WeakPtrs now to avoid callbacks back into the - // FrameGenerator during destruction of |compositor_frame_sink_|. - weak_factory_.InvalidateWeakPtrs(); compositor_frame_sink_.reset(); } @@ -107,6 +103,7 @@ const cc::ReturnedResourceArray& resources) { // Nothing to do here because FrameGenerator CompositorFrames don't reference // any resources. + DCHECK(resources.empty()); } void FrameGenerator::WillDrawSurface() {
diff --git a/services/ui/ws/frame_generator.h b/services/ui/ws/frame_generator.h index 6b4afe5..1275a2a 100644 --- a/services/ui/ws/frame_generator.h +++ b/services/ui/ws/frame_generator.h
@@ -82,8 +82,6 @@ mojo::Binding<cc::mojom::MojoCompositorFrameSinkClient> binding_; - base::WeakPtrFactory<FrameGenerator> weak_factory_; - DISALLOW_COPY_AND_ASSIGN(FrameGenerator); };
diff --git a/services/ui/ws/server_window.cc b/services/ui/ws/server_window.cc index d52bf66e..64f79e2 100644 --- a/services/ui/ws/server_window.cc +++ b/services/ui/ws/server_window.cc
@@ -31,8 +31,10 @@ transient_parent_(nullptr), is_modal_(false), visible_(false), - cursor_id_(mojom::Cursor::CURSOR_NULL), - non_client_cursor_id_(mojom::Cursor::CURSOR_NULL), + // Default to POINTER as CURSOR_NULL doesn't change the cursor, it leaves + // the last non-null cursor. + cursor_id_(mojom::Cursor::POINTER), + non_client_cursor_id_(mojom::Cursor::POINTER), opacity_(1), can_focus_(true), properties_(properties),
diff --git a/services/ui/ws/server_window_compositor_frame_sink_manager.cc b/services/ui/ws/server_window_compositor_frame_sink_manager.cc index 5b2da17c..29cd7e9 100644 --- a/services/ui/ws/server_window_compositor_frame_sink_manager.cc +++ b/services/ui/ws/server_window_compositor_frame_sink_manager.cc
@@ -109,10 +109,6 @@ frame_sink_data_->compositor_frame_sink->RemoveChildFrameSink(frame_sink_id); } -bool ServerWindowCompositorFrameSinkManager::HasCompositorFrameSink() const { - return !!frame_sink_data_; -} - gfx::Size ServerWindowCompositorFrameSinkManager::GetLatestFrameSize() const { if (!frame_sink_data_) return gfx::Size(); @@ -120,14 +116,6 @@ return frame_sink_data_->latest_submitted_surface_info.size_in_pixels(); } -cc::SurfaceId ServerWindowCompositorFrameSinkManager::GetLatestSurfaceId() - const { - if (!frame_sink_data_) - return cc::SurfaceId(); - - return frame_sink_data_->latest_submitted_surface_info.id(); -} - void ServerWindowCompositorFrameSinkManager::SetLatestSurfaceInfo( const cc::SurfaceInfo& surface_info) { if (!frame_sink_data_)
diff --git a/services/ui/ws/server_window_compositor_frame_sink_manager.h b/services/ui/ws/server_window_compositor_frame_sink_manager.h index 3105e460..5a248c7 100644 --- a/services/ui/ws/server_window_compositor_frame_sink_manager.h +++ b/services/ui/ws/server_window_compositor_frame_sink_manager.h
@@ -63,12 +63,7 @@ void AddChildFrameSinkId(const cc::FrameSinkId& frame_sink_id); void RemoveChildFrameSinkId(const cc::FrameSinkId& frame_sink_id); - ServerWindow* window() { return window_; } - - bool HasCompositorFrameSink() const; - gfx::Size GetLatestFrameSize() const; - cc::SurfaceId GetLatestSurfaceId() const; void SetLatestSurfaceInfo(const cc::SurfaceInfo& surface_info); void OnRootChanged(ServerWindow* old_root, ServerWindow* new_root);
diff --git a/services/ui/ws/test_utils.cc b/services/ui/ws/test_utils.cc index acfbae9..c906176 100644 --- a/services/ui/ws/test_utils.cc +++ b/services/ui/ws/test_utils.cc
@@ -513,15 +513,16 @@ const gfx::Rect& root_window_bounds, const gfx::Rect& window_bounds) { WindowTree* wm_tree = window_server()->GetTreeWithId(1); - const ClientWindowId embed_window_id( - WindowIdToTransportId(WindowId(wm_tree->id(), 1))); + const ClientWindowId embed_window_id(WindowIdToTransportId( + WindowId(wm_tree->id(), next_primary_tree_window_id_++))); EXPECT_TRUE(wm_tree->NewWindow(embed_window_id, ServerWindow::Properties())); EXPECT_TRUE(wm_tree->SetWindowVisibility(embed_window_id, true)); EXPECT_TRUE(wm_tree->AddWindow(FirstRootId(wm_tree), embed_window_id)); display_->root_window()->SetBounds(root_window_bounds); mojom::WindowTreeClientPtr client; mojom::WindowTreeClientRequest client_request(&client); - wm_client_->Bind(std::move(client_request)); + ws_test_helper_.window_server_delegate()->last_client()->Bind( + std::move(client_request)); const uint32_t embed_flags = 0; wm_tree->Embed(embed_window_id, std::move(client), embed_flags); ServerWindow* embed_window = wm_tree->GetWindowByClientId(embed_window_id); @@ -547,7 +548,7 @@ ASSERT_TRUE(tree1 != nullptr); const ClientWindowId child1_id( WindowIdToTransportId(WindowId(tree1->id(), 1))); - EXPECT_TRUE(tree1->NewWindow(child1_id, ServerWindow::Properties())); + ASSERT_TRUE(tree1->NewWindow(child1_id, ServerWindow::Properties())); ServerWindow* child1 = tree1->GetWindowByClientId(child1_id); ASSERT_TRUE(child1); EXPECT_TRUE(tree1->AddWindow(ClientWindowIdForWindow(tree1, embed_window), @@ -634,7 +635,8 @@ return nullptr; if (!tree->AddWindow(parent_client_id, client_window_id)) return nullptr; - *client_id = client_window_id; + if (client_id) + *client_id = client_window_id; return tree->GetWindowByClientId(client_window_id); }
diff --git a/services/ui/ws/test_utils.h b/services/ui/ws/test_utils.h index b928869ed..29d65cd 100644 --- a/services/ui/ws/test_utils.h +++ b/services/ui/ws/test_utils.h
@@ -612,6 +612,7 @@ // Creates a secondary tree, embedded as a child of |embed_window|. The // resulting |window| is setup for event targeting, with bounds // |window_bounds|. + // TODO(sky): rename and cleanup. This doesn't really create a new tree. void CreateSecondaryTree(ServerWindow* embed_window, const gfx::Rect& window_bounds, TestWindowTreeClient** out_client, @@ -640,6 +641,7 @@ TestDisplayBinding* display_binding_ = nullptr; // Owned by WindowServer's DisplayManager. Display* display_ = nullptr; + ClientSpecificId next_primary_tree_window_id_ = 1; DISALLOW_COPY_AND_ASSIGN(WindowEventTargetingHelper); }; @@ -676,7 +678,7 @@ ServerWindow* NewWindowInTree(WindowTree* tree, ClientWindowId* client_id); ServerWindow* NewWindowInTreeWithParent(WindowTree* tree, ServerWindow* parent, - ClientWindowId* client_id); + ClientWindowId* client_id = nullptr); } // namespace test } // namespace ws
diff --git a/services/ui/ws/window_manager_state_unittest.cc b/services/ui/ws/window_manager_state_unittest.cc index 1de0f60..7a502a9 100644 --- a/services/ui/ws/window_manager_state_unittest.cc +++ b/services/ui/ws/window_manager_state_unittest.cc
@@ -65,12 +65,6 @@ TestWindowTreeClient* wm_client() { return window_event_targeting_helper_.wm_client(); } - TestWindowTreeClient* last_tree_client() { - return window_event_targeting_helper_.last_window_tree_client(); - } - WindowTree* last_tree() { - return window_event_targeting_helper_.last_binding()->tree(); - } WindowManagerState* window_manager_state() { return window_manager_state_; } WindowServer* window_server() { return window_event_targeting_helper_.window_server(); @@ -571,22 +565,28 @@ } TEST_F(WindowManagerStateTest, CursorResetOverNoTarget) { - TestChangeTracker* tracker = window_tree_client()->tracker(); ASSERT_EQ(1u, window_server()->display_manager()->displays().size()); Display* display = *(window_server()->display_manager()->displays().begin()); DisplayTestApi display_test_api(display); - // This test assumes the default is not a pointer, otherwise it can't detect - // the change. - EXPECT_NE(ui::mojom::Cursor::POINTER, display_test_api.last_cursor()); + const ClientWindowId child_window_id(11); + window_tree()->NewWindow(child_window_id, ServerWindow::Properties()); + ServerWindow* child_window = + window_tree()->GetWindowByClientId(child_window_id); + window_tree()->AddWindow(FirstRootId(window_tree()), child_window_id); + child_window->SetVisible(true); + child_window->SetBounds(gfx::Rect(0, 0, 20, 20)); + child_window->parent()->SetPredefinedCursor(ui::mojom::Cursor::COPY); + EXPECT_EQ(ui::mojom::Cursor::COPY, display_test_api.last_cursor()); + // Move the mouse outside the bounds of the child, so that the mouse is not + // over any valid windows. Cursor should change to POINTER. ui::PointerEvent move( - ui::ET_POINTER_MOVED, gfx::Point(), gfx::Point(), 0, 0, 0, + ui::ET_POINTER_MOVED, gfx::Point(25, 25), gfx::Point(25, 25), 0, 0, 0, ui::PointerDetails(EventPointerType::POINTER_TYPE_MOUSE), base::TimeTicks()); window_manager_state()->ProcessEvent(move); // The event isn't over a valid target, which should trigger resetting the // cursor to POINTER. EXPECT_EQ(ui::mojom::Cursor::POINTER, display_test_api.last_cursor()); - EXPECT_TRUE(tracker->changes()->empty()); } } // namespace test
diff --git a/services/ui/ws/window_server.cc b/services/ui/ws/window_server.cc index 4a2cb7d6..9ab1795 100644 --- a/services/ui/ws/window_server.cc +++ b/services/ui/ws/window_server.cc
@@ -596,7 +596,7 @@ EventDispatcher* event_dispatcher = display_root->window_manager_state()->event_dispatcher(); - if (window != event_dispatcher->mouse_cursor_source_window()) + if (window != event_dispatcher->GetWindowForMouseCursor()) return; event_dispatcher->UpdateNonClientAreaForCurrentWindow();
diff --git a/services/ui/ws/window_server.h b/services/ui/ws/window_server.h index 17c15011..32fc0d66 100644 --- a/services/ui/ws/window_server.h +++ b/services/ui/ws/window_server.h
@@ -123,7 +123,7 @@ // Returns true if OnTreeMessagedClient() was invoked for id. bool DidTreeMessageClient(ClientSpecificId id) const; - // Returns the WindowTree that has |id| as a root. + // Returns the WindowTree that has |window| as a root. WindowTree* GetTreeWithRoot(const ServerWindow* window) { return const_cast<WindowTree*>( const_cast<const WindowServer*>(this)->GetTreeWithRoot(window));
diff --git a/services/ui/ws/window_tree_unittest.cc b/services/ui/ws/window_tree_unittest.cc index 356e40d..9513eb5 100644 --- a/services/ui/ws/window_tree_unittest.cc +++ b/services/ui/ws/window_tree_unittest.cc
@@ -133,9 +133,6 @@ return window_event_targeting_helper_.cursor(); } Display* display() { return window_event_targeting_helper_.display(); } - TestWindowTreeBinding* last_binding() { - return window_event_targeting_helper_.last_binding(); - } TestWindowTreeClient* last_window_tree_client() { return window_event_targeting_helper_.last_window_tree_client(); } @@ -476,7 +473,8 @@ // dispatched. This is only to place the mouse cursor over that window though. DispatchEventAndAckImmediately(CreateMouseMoveEvent(21, 22)); - window->SetPredefinedCursor(mojom::Cursor::IBEAM); + // Set the cursor on the parent as that is where the cursor is picked up from. + window->parent()->SetPredefinedCursor(mojom::Cursor::IBEAM); // Because the cursor is over the window when SetCursor was called, we should // have immediately changed the cursor. @@ -492,7 +490,8 @@ // Let's create a pointer event outside the window and then move the pointer // inside. DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5)); - window->SetPredefinedCursor(mojom::Cursor::IBEAM); + // Set the cursor on the parent as that is where the cursor is picked up from. + window->parent()->SetPredefinedCursor(mojom::Cursor::IBEAM); EXPECT_EQ(mojom::Cursor::POINTER, cursor_id()); DispatchEventAndAckImmediately(CreateMouseMoveEvent(21, 22)); @@ -525,7 +524,8 @@ // Start with the cursor outside the window. Setting the cursor shouldn't // change the cursor. DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5)); - window->SetPredefinedCursor(mojom::Cursor::IBEAM); + // Set the cursor on the parent as that is where the cursor is picked up from. + window->parent()->SetPredefinedCursor(mojom::Cursor::IBEAM); EXPECT_EQ(mojom::Cursor::POINTER, cursor_id()); // Move the pointer to the inside of the window @@ -543,7 +543,7 @@ // Release the cursor. We should now adapt the cursor of the window // underneath the pointer. DispatchEventAndAckImmediately(CreateMouseUpEvent(5, 5)); - EXPECT_EQ(mojom::Cursor::CURSOR_NULL, cursor_id()); + EXPECT_EQ(mojom::Cursor::POINTER, cursor_id()); } TEST_F(WindowTreeTest, ChangingWindowBoundsChangesCursor) { @@ -554,7 +554,8 @@ // Put the cursor just outside the bounds of the window. DispatchEventAndAckImmediately(CreateMouseMoveEvent(41, 41)); - window->SetPredefinedCursor(mojom::Cursor::IBEAM); + // Sets the cursor on the root as that is where the cursor is picked up from. + window->parent()->SetPredefinedCursor(mojom::Cursor::IBEAM); EXPECT_EQ(mojom::Cursor::POINTER, cursor_id()); // Expand the bounds of the window so they now include where the cursor now @@ -564,38 +565,72 @@ // Contract the bounds again. window->SetBounds(gfx::Rect(20, 20, 20, 20)); - EXPECT_EQ(mojom::Cursor::CURSOR_NULL, cursor_id()); + EXPECT_EQ(mojom::Cursor::POINTER, cursor_id()); } TEST_F(WindowTreeTest, WindowReorderingChangesCursor) { - TestWindowTreeClient* embed_client = nullptr; - WindowTree* tree = nullptr; - ServerWindow* window1 = nullptr; - EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window1)); + // Setup two trees parented to the root with the same bounds. + ServerWindow* embed_window1 = + window_event_targeting_helper_.CreatePrimaryTree( + gfx::Rect(0, 0, 200, 200), gfx::Rect(0, 0, 50, 50)); + ServerWindow* embed_window2 = + window_event_targeting_helper_.CreatePrimaryTree( + gfx::Rect(0, 0, 200, 200), gfx::Rect(0, 0, 50, 50)); - // Create a second window right over the first. - const ClientWindowId embed_window_id(FirstRootId(tree)); - const ClientWindowId child2_id(BuildClientWindowId(tree, 2)); - EXPECT_TRUE(tree->NewWindow(child2_id, ServerWindow::Properties())); - ServerWindow* child2 = tree->GetWindowByClientId(child2_id); - ASSERT_TRUE(child2); - EXPECT_TRUE(tree->AddWindow(embed_window_id, child2_id)); - child2->SetVisible(true); - child2->SetBounds(gfx::Rect(20, 20, 20, 20)); - - // Give each window a different cursor. - window1->SetPredefinedCursor(mojom::Cursor::IBEAM); - child2->SetPredefinedCursor(mojom::Cursor::HAND); - - // We expect window2 to be over window1 now. - DispatchEventAndAckImmediately(CreateMouseMoveEvent(22, 22)); - EXPECT_EQ(mojom::Cursor::HAND, cursor_id()); - - // But when we put window2 at the bottom, we should adapt window1's cursor. - child2->parent()->StackChildAtBottom(child2); + ASSERT_EQ(embed_window1->parent(), embed_window2->parent()); + embed_window1->set_event_targeting_policy( + mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS); + embed_window2->set_event_targeting_policy( + mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS); + embed_window1->SetPredefinedCursor(mojom::Cursor::IBEAM); + embed_window2->SetPredefinedCursor(mojom::Cursor::CROSS); + DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5)); + // Cursor should match that of top-most window, which is |embed_window2|. + EXPECT_EQ(mojom::Cursor::CROSS, cursor_id()); + // Move |embed_window1| on top, cursor should now match it. + embed_window1->parent()->StackChildAtTop(embed_window1); EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id()); } +// Assertions around moving cursor between trees with roots. +TEST_F(WindowTreeTest, CursorMultipleTrees) { + // Setup two trees parented to the root with the same bounds. + ServerWindow* embed_window1 = + window_event_targeting_helper_.CreatePrimaryTree( + gfx::Rect(0, 0, 200, 200), gfx::Rect(0, 0, 10, 10)); + ServerWindow* embed_window2 = + window_event_targeting_helper_.CreatePrimaryTree( + gfx::Rect(0, 0, 200, 200), gfx::Rect(20, 20, 20, 20)); + embed_window1->set_event_targeting_policy( + mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS); + embed_window2->set_event_targeting_policy( + mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS); + embed_window2->parent()->set_event_targeting_policy( + mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS); + embed_window1->SetPredefinedCursor(mojom::Cursor::IBEAM); + embed_window2->SetPredefinedCursor(mojom::Cursor::CROSS); + embed_window1->parent()->SetPredefinedCursor(mojom::Cursor::COPY); + + // Create a child of |embed_window1|. + ServerWindow* embed_window1_child = NewWindowInTreeWithParent( + window_server()->GetTreeWithRoot(embed_window1), embed_window1); + ASSERT_TRUE(embed_window1_child); + embed_window1_child->SetBounds(gfx::Rect(0, 0, 10, 10)); + embed_window1_child->SetVisible(true); + + // Move mouse into |embed_window1|. + DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5)); + EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id()); + + // Move mouse into |embed_window2|. + DispatchEventAndAckImmediately(CreateMouseMoveEvent(25, 25)); + EXPECT_EQ(mojom::Cursor::CROSS, cursor_id()); + + // Move mouse into area between, which should use cursor set on parent. + DispatchEventAndAckImmediately(CreateMouseMoveEvent(15, 15)); + EXPECT_EQ(mojom::Cursor::COPY, cursor_id()); +} + TEST_F(WindowTreeTest, EventAck) { const ClientWindowId embed_window_id = BuildClientWindowId(wm_tree(), 1); EXPECT_TRUE(
diff --git a/storage/OWNERS b/storage/OWNERS index ef9e0f02..1dd3e432 100644 --- a/storage/OWNERS +++ b/storage/OWNERS
@@ -1,9 +1,7 @@ -darin@chromium.org +dmurph@chromium.org jsbell@chromium.org kinuko@chromium.org michaeln@chromium.org -piman@chromium.org -danakj@chromium.org # TEAM: storage-dev@chromium.org # COMPONENT: Blink>Storage
diff --git a/storage/browser/quota/quota_manager.cc b/storage/browser/quota/quota_manager.cc index 0c536bc..b9452e44d 100644 --- a/storage/browser/quota/quota_manager.cc +++ b/storage/browser/quota/quota_manager.cc
@@ -1638,16 +1638,15 @@ void QuotaManager::PostTaskAndReplyWithResultForDBThread( const tracked_objects::Location& from_here, - const base::Callback<bool(QuotaDatabase*)>& task, - const base::Callback<void(bool)>& reply) { + base::Callback<bool(QuotaDatabase*)> task, + base::Callback<void(bool)> reply) { // Deleting manager will post another task to DB thread to delete // |database_|, therefore we can be sure that database_ is alive when this // task runs. base::PostTaskAndReplyWithResult( - db_thread_.get(), - from_here, - base::Bind(task, base::Unretained(database_.get())), - reply); + db_thread_.get(), from_here, + base::Bind(std::move(task), base::Unretained(database_.get())), + std::move(reply)); } // static
diff --git a/storage/browser/quota/quota_manager.h b/storage/browser/quota/quota_manager.h index fd5c883..001c650 100644 --- a/storage/browser/quota/quota_manager.h +++ b/storage/browser/quota/quota_manager.h
@@ -401,8 +401,8 @@ void PostTaskAndReplyWithResultForDBThread( const tracked_objects::Location& from_here, - const base::Callback<bool(QuotaDatabase*)>& task, - const base::Callback<void(bool)>& reply); + base::Callback<bool(QuotaDatabase*)> task, + base::Callback<void(bool)> reply); static std::tuple<int64_t, int64_t> CallGetVolumeInfo( GetVolumeInfoFn get_volume_info_fn,
diff --git a/testing/android/native_test/native_test_jni_onload.cc b/testing/android/native_test/native_test_jni_onload.cc index 8fecc44..01c3aba 100644 --- a/testing/android/native_test/native_test_jni_onload.cc +++ b/testing/android/native_test/native_test_jni_onload.cc
@@ -4,16 +4,19 @@ #include "base/android/base_jni_onload.h" #include "base/android/jni_android.h" +#include "base/android/library_loader/library_loader_hooks.h" #include "base/bind.h" #include "testing/android/native_test/native_test_launcher.h" namespace { -bool RegisterJNI(JNIEnv* env) { +bool RegisterJNI(JNIEnv *env) { return testing::android::RegisterNativeTestJNI(env); } -bool Init() { +bool NativeInit() { + if (!base::android::OnJNIOnLoadInit()) + return false; testing::android::InstallHandlers(); return true; } @@ -23,16 +26,11 @@ // This is called by the VM when the shared library is first loaded. JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { - std::vector<base::android::RegisterCallback> register_callbacks; - register_callbacks.push_back(base::Bind(&RegisterJNI)); - - if (!base::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks)) + base::android::InitVM(vm); + JNIEnv* env = base::android::AttachCurrentThread(); + if (!base::android::OnJNIOnLoadRegisterJNI(env) || !RegisterJNI(env) || + !NativeInit()) { return -1; - - std::vector<base::android::InitCallback> init_callbacks; - init_callbacks.push_back(base::Bind(&Init)); - if (!base::android::OnJNIOnLoadInit(init_callbacks)) - return -1; - + } return JNI_VERSION_1_4; }
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json index 3fff277..eedc346 100644 --- a/testing/buildbot/chromium.gpu.fyi.json +++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -5384,2533 +5384,6 @@ } ] }, - "Mac 10.10 Debug (AMD)": { - "gtest_tests": [ - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - }, - "test": "angle_end2end_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - }, - "test": "angle_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - }, - "test": "audio_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - }, - "test": "gl_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - }, - "test": "gl_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - }, - "test": "gles2_conform_test", - "use_xvfb": false - } - ], - "isolated_scripts": [ - { - "args": [ - "context_lost", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "context_lost_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - } - }, - { - "args": [ - "depth_capture", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "depth_capture_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - } - }, - { - "args": [ - "gpu_process", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "gpu_process_launch_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - } - }, - { - "args": [ - "hardware_accelerated_feature", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "hardware_accelerated_feature_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - } - }, - { - "args": [ - "maps", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "maps_pixel_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - } - }, - { - "args": [ - "pixel", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--refimg-cloud-storage-bucket", - "chromium-gpu-archive/reference-images", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "pixel_test", - "non_precommit_args": [ - "--upload-refimg-to-cloud-storage" - ], - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "precommit_args": [ - "--download-refimg-from-cloud-storage" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - } - }, - { - "args": [ - "screenshot_sync", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "screenshot_sync_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - } - }, - { - "args": [ - "trace_test", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "trace_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - } - }, - { - "args": [ - "webgl_conformance", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "webgl_conformance_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - } - } - ] - }, - "Mac 10.10 Debug (Intel)": { - "gtest_tests": [ - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - }, - "test": "angle_end2end_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - }, - "test": "angle_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - }, - "test": "audio_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - }, - "test": "gl_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - }, - "test": "gl_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - }, - "test": "gles2_conform_test", - "use_xvfb": false - } - ], - "isolated_scripts": [ - { - "args": [ - "context_lost", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "context_lost_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "depth_capture", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "depth_capture_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "gpu_process", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "gpu_process_launch_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "hardware_accelerated_feature", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "hardware_accelerated_feature_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "maps", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "maps_pixel_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "pixel", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--refimg-cloud-storage-bucket", - "chromium-gpu-archive/reference-images", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "pixel_test", - "non_precommit_args": [ - "--upload-refimg-to-cloud-storage" - ], - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "precommit_args": [ - "--download-refimg-from-cloud-storage" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "screenshot_sync", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "screenshot_sync_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "trace_test", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "trace_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "webgl_conformance", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "webgl_conformance_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - } - ] - }, - "Mac 10.10 Release (AMD)": { - "gtest_tests": [ - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - }, - "test": "angle_end2end_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - }, - "test": "angle_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - }, - "test": "audio_unittests", - "use_xvfb": false - }, - { - "args": [ - "--enable-gpu", - "--test-launcher-jobs=1", - "--gtest_filter=CastStreamingApiTestWithPixelOutput.EndToEnd*:TabCaptureApiPixelTest.EndToEnd*" - ], - "name": "tab_capture_end2end_tests", - "swarming": { - "can_use_on_swarming_builders": false - }, - "test": "browser_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - }, - "test": "gl_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - }, - "test": "gl_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - }, - "test": "gles2_conform_test", - "use_xvfb": false - } - ], - "isolated_scripts": [ - { - "args": [ - "context_lost", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "context_lost_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - } - }, - { - "args": [ - "depth_capture", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "depth_capture_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - } - }, - { - "args": [ - "gpu_process", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "gpu_process_launch_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - } - }, - { - "args": [ - "hardware_accelerated_feature", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "hardware_accelerated_feature_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - } - }, - { - "args": [ - "maps", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "maps_pixel_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - } - }, - { - "args": [ - "pixel", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--refimg-cloud-storage-bucket", - "chromium-gpu-archive/reference-images", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "pixel_test", - "non_precommit_args": [ - "--upload-refimg-to-cloud-storage" - ], - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "precommit_args": [ - "--download-refimg-from-cloud-storage" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - } - }, - { - "args": [ - "screenshot_sync", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "screenshot_sync_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - } - }, - { - "args": [ - "trace_test", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "trace_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - } - }, - { - "args": [ - "webgl_conformance", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--webgl-conformance-version=2.0.1", - "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "webgl2_conformance_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ], - "shards": 15 - } - }, - { - "args": [ - "webgl_conformance", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "webgl_conformance_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:679e", - "os": "Mac-10.10" - } - ] - } - } - ] - }, - "Mac 10.10 Release (Intel)": { - "gtest_tests": [ - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - }, - "test": "angle_end2end_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - }, - "test": "angle_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - }, - "test": "audio_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - }, - "test": "gl_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - }, - "test": "gl_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - }, - "test": "gles2_conform_test", - "use_xvfb": false - }, - { - "override_compile_targets": [ - "tab_capture_end2end_tests_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - }, - "test": "tab_capture_end2end_tests", - "use_xvfb": false - } - ], - "isolated_scripts": [ - { - "args": [ - "context_lost", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "context_lost_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "depth_capture", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "depth_capture_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "gpu_process", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "gpu_process_launch_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "hardware_accelerated_feature", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "hardware_accelerated_feature_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "maps", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "maps_pixel_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "pixel", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--refimg-cloud-storage-bucket", - "chromium-gpu-archive/reference-images", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "pixel_test", - "non_precommit_args": [ - "--upload-refimg-to-cloud-storage" - ], - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "precommit_args": [ - "--download-refimg-from-cloud-storage" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "screenshot_sync", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "screenshot_sync_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "trace_test", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "trace_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "webgl_conformance", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--webgl-conformance-version=2.0.1", - "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "webgl2_conformance_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ], - "shards": 15 - } - }, - { - "args": [ - "webgl_conformance", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "webgl_conformance_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - } - ] - }, - "Mac 10.10 Retina Debug (AMD)": { - "gtest_tests": [ - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "angle_end2end_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "angle_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "audio_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "gl_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "gl_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "gles2_conform_test", - "use_xvfb": false - } - ], - "isolated_scripts": [ - { - "args": [ - "context_lost", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "context_lost_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "depth_capture", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "depth_capture_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "gpu_process", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "gpu_process_launch_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "hardware_accelerated_feature", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "hardware_accelerated_feature_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "maps", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "maps_pixel_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "pixel", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--refimg-cloud-storage-bucket", - "chromium-gpu-archive/reference-images", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "pixel_test", - "non_precommit_args": [ - "--upload-refimg-to-cloud-storage" - ], - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "precommit_args": [ - "--download-refimg-from-cloud-storage" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "screenshot_sync", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "screenshot_sync_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "trace_test", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "trace_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "webgl_conformance", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "webgl_conformance_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - } - ] - }, - "Mac 10.10 Retina Release (AMD)": { - "gtest_tests": [ - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "angle_end2end_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "angle_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "audio_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "gl_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "gl_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "gles2_conform_test", - "use_xvfb": false - }, - { - "override_compile_targets": [ - "tab_capture_end2end_tests_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "tab_capture_end2end_tests", - "use_xvfb": false - } - ], - "isolated_scripts": [ - { - "args": [ - "context_lost", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "context_lost_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "depth_capture", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "depth_capture_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "gpu_process", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "gpu_process_launch_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "hardware_accelerated_feature", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "hardware_accelerated_feature_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "maps", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "maps_pixel_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "pixel", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--refimg-cloud-storage-bucket", - "chromium-gpu-archive/reference-images", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "pixel_test", - "non_precommit_args": [ - "--upload-refimg-to-cloud-storage" - ], - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "precommit_args": [ - "--download-refimg-from-cloud-storage" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "screenshot_sync", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "screenshot_sync_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "trace_test", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "trace_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "webgl_conformance", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--webgl-conformance-version=2.0.1", - "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "webgl2_conformance_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ], - "shards": 15 - } - }, - { - "args": [ - "webgl_conformance", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "webgl_conformance_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - } - ] - }, - "Mac 10.11 Retina Release (AMD)": { - "gtest_tests": [ - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "angle_end2end_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "angle_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "audio_unittests", - "use_xvfb": false - }, - { - "args": [ - "--enable-gpu", - "--test-launcher-jobs=1", - "--gtest_filter=CastStreamingApiTestWithPixelOutput.EndToEnd*:TabCaptureApiPixelTest.EndToEnd*" - ], - "name": "tab_capture_end2end_tests", - "swarming": { - "can_use_on_swarming_builders": false - }, - "test": "browser_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "gl_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "gl_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "gles2_conform_test", - "use_xvfb": false - } - ], - "isolated_scripts": [ - { - "args": [ - "context_lost", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "context_lost_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "depth_capture", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "depth_capture_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "gpu_process", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "gpu_process_launch_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "hardware_accelerated_feature", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "hardware_accelerated_feature_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "maps", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "maps_pixel_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "pixel", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--refimg-cloud-storage-bucket", - "chromium-gpu-archive/reference-images", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "pixel_test", - "non_precommit_args": [ - "--upload-refimg-to-cloud-storage" - ], - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "precommit_args": [ - "--download-refimg-from-cloud-storage" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "screenshot_sync", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "screenshot_sync_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "trace_test", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "trace_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "webgl_conformance", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--webgl-conformance-version=2.0.1", - "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "webgl2_conformance_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ], - "shards": 15 - } - }, - { - "args": [ - "webgl_conformance", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "webgl_conformance_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": false, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - } - ] - }, "Mac Debug (Intel)": { "gtest_tests": [ { @@ -10548,352 +8021,6 @@ } ] }, - "Mac Retina Debug": { - "gtest_tests": [ - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "angle_end2end_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "angle_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "audio_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "gl_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "gl_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "gles2_conform_test", - "use_xvfb": false - } - ], - "isolated_scripts": [ - { - "args": [ - "context_lost", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "context_lost_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "depth_capture", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "depth_capture_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "gpu_process", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "gpu_process_launch_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "hardware_accelerated_feature", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "hardware_accelerated_feature_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "maps", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "maps_pixel_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "pixel", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--refimg-cloud-storage-bucket", - "chromium-gpu-archive/reference-images", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "pixel_test", - "non_precommit_args": [ - "--upload-refimg-to-cloud-storage" - ], - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "precommit_args": [ - "--download-refimg-from-cloud-storage" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "screenshot_sync", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "screenshot_sync_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "trace_test", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "trace_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "webgl_conformance", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "webgl_conformance_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - } - } - ] - }, "Mac Retina Debug (AMD)": { "gtest_tests": [ { @@ -11586,396 +8713,6 @@ } ] }, - "Mac Retina Release": { - "gtest_tests": [ - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "angle_end2end_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "angle_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "audio_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "gl_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "gl_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "gles2_conform_test", - "use_xvfb": false - }, - { - "override_compile_targets": [ - "tab_capture_end2end_tests_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "tab_capture_end2end_tests", - "use_xvfb": false - } - ], - "isolated_scripts": [ - { - "args": [ - "context_lost", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "context_lost_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "depth_capture", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "depth_capture_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "gpu_process", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "gpu_process_launch_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "hardware_accelerated_feature", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "hardware_accelerated_feature_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "maps", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "maps_pixel_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "pixel", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--refimg-cloud-storage-bucket", - "chromium-gpu-archive/reference-images", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "pixel_test", - "non_precommit_args": [ - "--upload-refimg-to-cloud-storage" - ], - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "precommit_args": [ - "--download-refimg-from-cloud-storage" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "screenshot_sync", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "screenshot_sync_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "trace_test", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "trace_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "webgl_conformance", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--webgl-conformance-version=2.0.1", - "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "webgl2_conformance_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ], - "shards": 15 - } - }, - { - "args": [ - "webgl_conformance", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "webgl_conformance_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:0fe9", - "hidpi": "1", - "os": "Mac" - } - ] - } - } - ] - }, "Mac Retina Release (AMD)": { "gtest_tests": [ {
diff --git a/testing/buildbot/chromium.gpu.json b/testing/buildbot/chromium.gpu.json index ae23c22..6c491b58 100644 --- a/testing/buildbot/chromium.gpu.json +++ b/testing/buildbot/chromium.gpu.json
@@ -587,1191 +587,6 @@ } ] }, - "Mac 10.10 Debug (Intel)": { - "gtest_tests": [ - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - }, - "test": "angle_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - }, - "test": "gl_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - }, - "test": "gl_unittests", - "use_xvfb": false - } - ], - "isolated_scripts": [ - { - "args": [ - "context_lost", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "context_lost_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "depth_capture", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "depth_capture_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "gpu_process", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "gpu_process_launch_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "hardware_accelerated_feature", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "hardware_accelerated_feature_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "maps", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "maps_pixel_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "pixel", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--refimg-cloud-storage-bucket", - "chromium-gpu-archive/reference-images", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "pixel_test", - "non_precommit_args": [ - "--upload-refimg-to-cloud-storage" - ], - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "precommit_args": [ - "--download-refimg-from-cloud-storage" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "screenshot_sync", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "screenshot_sync_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "trace_test", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "trace_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "webgl_conformance", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "webgl_conformance_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - } - ] - }, - "Mac 10.10 Release (Intel)": { - "gtest_tests": [ - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - }, - "test": "angle_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - }, - "test": "gl_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - }, - "test": "gl_unittests", - "use_xvfb": false - }, - { - "override_compile_targets": [ - "tab_capture_end2end_tests_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - }, - "test": "tab_capture_end2end_tests", - "use_xvfb": false - } - ], - "isolated_scripts": [ - { - "args": [ - "context_lost", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "context_lost_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "depth_capture", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "depth_capture_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "gpu_process", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "gpu_process_launch_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "hardware_accelerated_feature", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "hardware_accelerated_feature_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "maps", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "maps_pixel_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "pixel", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--refimg-cloud-storage-bucket", - "chromium-gpu-archive/reference-images", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "pixel_test", - "non_precommit_args": [ - "--upload-refimg-to-cloud-storage" - ], - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "precommit_args": [ - "--download-refimg-from-cloud-storage" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "screenshot_sync", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "screenshot_sync_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "trace_test", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "trace_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - }, - { - "args": [ - "webgl_conformance", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "webgl_conformance_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "os": "Mac-10.12" - } - ] - } - } - ] - }, - "Mac 10.10 Retina Debug (AMD)": { - "gtest_tests": [ - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "angle_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "gl_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "gl_unittests", - "use_xvfb": false - } - ], - "isolated_scripts": [ - { - "args": [ - "context_lost", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "context_lost_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "depth_capture", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "depth_capture_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "gpu_process", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "gpu_process_launch_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "hardware_accelerated_feature", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "hardware_accelerated_feature_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "maps", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "maps_pixel_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "pixel", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--refimg-cloud-storage-bucket", - "chromium-gpu-archive/reference-images", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "pixel_test", - "non_precommit_args": [ - "--upload-refimg-to-cloud-storage" - ], - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "precommit_args": [ - "--download-refimg-from-cloud-storage" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "screenshot_sync", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "screenshot_sync_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "trace_test", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "trace_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "webgl_conformance", - "--show-stdout", - "--browser=debug", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "webgl_conformance_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - } - ] - }, - "Mac 10.10 Retina Release (AMD)": { - "gtest_tests": [ - { - "args": [ - "--use-gpu-in-tests", - "--test-launcher-retry-limit=0" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "angle_unittests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "gl_tests", - "use_xvfb": false - }, - { - "args": [ - "--use-gpu-in-tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "gl_unittests", - "use_xvfb": false - }, - { - "override_compile_targets": [ - "tab_capture_end2end_tests_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - }, - "test": "tab_capture_end2end_tests", - "use_xvfb": false - } - ], - "isolated_scripts": [ - { - "args": [ - "context_lost", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "context_lost_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "depth_capture", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "depth_capture_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "gpu_process", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "gpu_process_launch_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "hardware_accelerated_feature", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "hardware_accelerated_feature_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "maps", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "maps_pixel_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "pixel", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--refimg-cloud-storage-bucket", - "chromium-gpu-archive/reference-images", - "--os-type", - "mac", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "pixel_test", - "non_precommit_args": [ - "--upload-refimg-to-cloud-storage" - ], - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "precommit_args": [ - "--download-refimg-from-cloud-storage" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "screenshot_sync", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "screenshot_sync_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "trace_test", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "trace_test", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - }, - { - "args": [ - "webgl_conformance", - "--show-stdout", - "--browser=release", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" - ], - "isolate_name": "telemetry_gpu_integration_test", - "name": "webgl_conformance_tests", - "override_compile_targets": [ - "telemetry_gpu_integration_test_run" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "hidpi": "1", - "os": "Mac" - } - ] - } - } - ] - }, "Mac Debug (Intel)": { "gtest_tests": [ {
diff --git a/testing/libfuzzer/archive_corpus.py b/testing/libfuzzer/archive_corpus.py index 5eb92b3..9d3bf93 100755 --- a/testing/libfuzzer/archive_corpus.py +++ b/testing/libfuzzer/archive_corpus.py
@@ -19,16 +19,19 @@ def main(): parser = argparse.ArgumentParser(description="Generate fuzzer config.") - parser.add_argument('--corpus', required=True) - parser.add_argument('--output', required=True) + parser.add_argument('corpus_directories', metavar='corpus_dir', type=str, + nargs='+') + parser.add_argument('--output', metavar='output_archive_name.zip', + required=True) args = parser.parse_args() corpus_files = [] - for (dirpath, _, filenames) in os.walk(args.corpus): - for filename in filenames: - full_filename = os.path.join(dirpath, filename) - corpus_files.append(full_filename) + for directory in args.corpus_directories: + for (dirpath, _, filenames) in os.walk(directory): + for filename in filenames: + full_filename = os.path.join(dirpath, filename) + corpus_files.append(full_filename) with zipfile.ZipFile(args.output, 'w') as z: # Turn warnings into errors to interrupt the build: crbug.com/653920.
diff --git a/testing/libfuzzer/efficient_fuzzer.md b/testing/libfuzzer/efficient_fuzzer.md index 7c3be85..b14c7c0 100644 --- a/testing/libfuzzer/efficient_fuzzer.md +++ b/testing/libfuzzer/efficient_fuzzer.md
@@ -58,6 +58,19 @@ } ``` +You may specify multiple seed corpus directories via `seed_corpuses` attribute: + +``` +fuzzer_test("my_protocol_fuzzer") { + ... + seed_corpuses = [ "src/fuzz/testcases", "src/unittest/data" ] + ... +} +``` + +All files found in the directories and their subdirectories will be archived +into `%YOUR_FUZZER_NAME%_seed_corpus.zip` output archive. + If you don't want to store seed corpus in Chromium repository, you can upload corpus to Google Cloud Storage bucket used by ClusterFuzz:
diff --git a/testing/libfuzzer/fuzzer_test.gni b/testing/libfuzzer/fuzzer_test.gni index bfdee49c..8f4ef6e 100644 --- a/testing/libfuzzer/fuzzer_test.gni +++ b/testing/libfuzzer/fuzzer_test.gni
@@ -37,21 +37,34 @@ test_deps += invoker.deps } - if (defined(invoker.seed_corpus)) { + if (defined(invoker.seed_corpus) || defined(invoker.seed_corpuses)) { + assert(!(defined(invoker.seed_corpus) && defined(invoker.seed_corpuses)), + "Do not use both seed_corpus and seed_corpuses for $target_name.") + out = "$root_build_dir/$target_name" + "_seed_corpus.zip" action(target_name + "_seed_corpus") { script = "//testing/libfuzzer/archive_corpus.py" + args = [ - "--corpus", - rebase_path(invoker.seed_corpus), "--output", rebase_path(out), ] + if (defined(invoker.seed_corpus)) { + args += [ rebase_path(invoker.seed_corpus) ] + } + + if (defined(invoker.seed_corpuses)) { + foreach(seed_corpus_path, invoker.seed_corpuses) { + args += [ rebase_path(seed_corpus_path) ] + } + } + outputs = [ out, ] + deps = [ "//testing/libfuzzer:seed_corpus", ]
diff --git a/testing/libfuzzer/tests/BUILD.gn b/testing/libfuzzer/tests/BUILD.gn index d0b1c4c..07ecda40 100644 --- a/testing/libfuzzer/tests/BUILD.gn +++ b/testing/libfuzzer/tests/BUILD.gn
@@ -13,6 +13,8 @@ ] deps = [ ":test_config_and_dict", + ":test_config_and_seed_corpus", + ":test_config_and_seed_corpuses", ":test_config_only", ":test_dict_from_subdir", ":test_dict_only", @@ -23,6 +25,7 @@ ] data_deps = [ ":check_fuzzer_config", + ":check_seed_corpus_archive", ] } @@ -55,6 +58,31 @@ ] } +fuzzer_test("test_config_and_seed_corpus") { + sources = [ + "../fuzzers/empty_fuzzer.cc", + ] + seed_corpus = "test_corpus" + libfuzzer_options = [ + "some_test_option=test_value", + "max_len=1024", + ] +} + +fuzzer_test("test_config_and_seed_corpuses") { + sources = [ + "../fuzzers/empty_fuzzer.cc", + ] + seed_corpuses = [ + "test_corpus", + "test_corpus_2", + ] + libfuzzer_options = [ + "some_test_option=another_test_value", + "max_len=1337", + ] +} + fuzzer_test("test_dict_from_subdir") { sources = [ "../fuzzers/empty_fuzzer.cc", @@ -70,3 +98,12 @@ "$root_build_dir/check_fuzzer_config.py", ] } + +copy("check_seed_corpus_archive") { + sources = [ + "check_seed_corpus_archive.py", + ] + outputs = [ + "$root_build_dir/check_seed_corpus_archive.py", + ] +}
diff --git a/testing/libfuzzer/tests/check_seed_corpus_archive.py b/testing/libfuzzer/tests/check_seed_corpus_archive.py new file mode 100755 index 0000000..5bbabd4e --- /dev/null +++ b/testing/libfuzzer/tests/check_seed_corpus_archive.py
@@ -0,0 +1,20 @@ +#!/usr/bin/python2 +# 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 that prints out number of files in given zip-archive. Used for testing. + +import ConfigParser +import os +import sys +import zipfile + +seed_corpus_archive_path = os.path.join(os.path.dirname(sys.argv[0]), + sys.argv[1]) + +if not os.path.exists(seed_corpus_archive_path): + sys.exit(-1) + +archive = zipfile.ZipFile(seed_corpus_archive_path) +sys.stdout.write('%d\n' % len(archive.namelist()))
diff --git a/testing/libfuzzer/tests/fuzzer_launcher_test.cc b/testing/libfuzzer/tests/fuzzer_launcher_test.cc index 5c9a3e1..625a821 100644 --- a/testing/libfuzzer/tests/fuzzer_launcher_test.cc +++ b/testing/libfuzzer/tests/fuzzer_launcher_test.cc
@@ -79,6 +79,78 @@ } +TEST(FuzzerConfigTest, ConfigAndSeedCorpus) { + // Test of .options file for fuzzer with libfuzzer_options and seed corpus. + base::FilePath exe_path; + PathService::Get(base::FILE_EXE, &exe_path); + std::string launcher_path = + exe_path.DirName().Append("check_fuzzer_config.py").value(); + + std::string output; + base::CommandLine cmd( + {{launcher_path, "test_config_and_seed_corpus.options"}}); + bool success = base::GetAppOutputAndError(cmd, &output); + EXPECT_TRUE(success); + std::vector<std::string> fuzzer_args = base::SplitString( + output, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + + EXPECT_EQ(2UL, fuzzer_args.size()); + + EXPECT_EQ(fuzzer_args[0], "some_test_option=test_value"); + EXPECT_EQ(fuzzer_args[1], "max_len=1024"); + + // Test seed_corpus archive. + launcher_path = + exe_path.DirName().Append("check_seed_corpus_archive.py").value(); + + cmd = base::CommandLine( + {{launcher_path, "test_config_and_seed_corpus_seed_corpus.zip"}}); + success = base::GetAppOutputAndError(cmd, &output); + EXPECT_TRUE(success); + std::vector<std::string> seed_corpus_info = base::SplitString( + output, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + + EXPECT_EQ(1UL, seed_corpus_info.size()); + EXPECT_EQ(seed_corpus_info[0], "3"); +} + + +TEST(FuzzerConfigTest, ConfigAndSeedCorpuses) { + // Test of .options file for fuzzer with libfuzzer_options and seed corpuses. + base::FilePath exe_path; + PathService::Get(base::FILE_EXE, &exe_path); + std::string launcher_path = + exe_path.DirName().Append("check_fuzzer_config.py").value(); + + std::string output; + base::CommandLine cmd( + {{launcher_path, "test_config_and_seed_corpuses.options"}}); + bool success = base::GetAppOutputAndError(cmd, &output); + EXPECT_TRUE(success); + std::vector<std::string> fuzzer_args = base::SplitString( + output, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + + EXPECT_EQ(2UL, fuzzer_args.size()); + + EXPECT_EQ(fuzzer_args[0], "some_test_option=another_test_value"); + EXPECT_EQ(fuzzer_args[1], "max_len=1337"); + + // Test seed_corpus archive. + launcher_path = + exe_path.DirName().Append("check_seed_corpus_archive.py").value(); + + cmd = base::CommandLine( + {{launcher_path, "test_config_and_seed_corpuses_seed_corpus.zip"}}); + success = base::GetAppOutputAndError(cmd, &output); + EXPECT_TRUE(success); + std::vector<std::string> seed_corpus_info = base::SplitString( + output, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + + EXPECT_EQ(1UL, seed_corpus_info.size()); + EXPECT_EQ(seed_corpus_info[0], "5"); +} + + TEST(FuzzerConfigTest, DictSubdir) { // Test of auto-generated .options file for fuzzer with dict in sub-directory. base::FilePath exe_path;
diff --git a/testing/libfuzzer/tests/test_corpus/f1 b/testing/libfuzzer/tests/test_corpus/f1 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/testing/libfuzzer/tests/test_corpus/f1
diff --git a/testing/libfuzzer/tests/test_corpus/f2 b/testing/libfuzzer/tests/test_corpus/f2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/testing/libfuzzer/tests/test_corpus/f2
diff --git a/testing/libfuzzer/tests/test_corpus/f3 b/testing/libfuzzer/tests/test_corpus/f3 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/testing/libfuzzer/tests/test_corpus/f3
diff --git a/testing/libfuzzer/tests/test_corpus_2/f1 b/testing/libfuzzer/tests/test_corpus_2/f1 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/testing/libfuzzer/tests/test_corpus_2/f1
diff --git a/testing/libfuzzer/tests/test_corpus_2/test_corpus_subdir/f1 b/testing/libfuzzer/tests/test_corpus_2/test_corpus_subdir/f1 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/testing/libfuzzer/tests/test_corpus_2/test_corpus_subdir/f1
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 91adfb3..74f62a5 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -744,6 +744,21 @@ ] } ], + "EnableWelcomeWin10": [ + { + "platforms": [ + "win" + ], + "experiments": [ + { + "name": "Inline", + "enable_features": [ + "EnableWelcomeWin10" + ] + } + ] + } + ], "ExpectCTReporting": [ { "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation index a8d1806..1654c76 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
@@ -13,10 +13,8 @@ crbug.com/575210 external/wpt/html/browsers/history/the-location-interface/security_location_0.htm [ Failure ] # https://crbug.com/551000: PlzNavigate: DevTools support -crbug.com/551000 http/tests/inspector/extensions-ignore-cache.html [ Failure ] crbug.com/551000 http/tests/inspector/extensions-network-redirect.html [ Timeout ] crbug.com/551000 http/tests/inspector/network/x-frame-options-deny.html [ Failure ] -crbug.com/551000 virtual/mojo-loading/http/tests/inspector/extensions-ignore-cache.html [ Failure ] crbug.com/551000 virtual/mojo-loading/http/tests/inspector/extensions-network-redirect.html [ Timeout ] crbug.com/551000 virtual/mojo-loading/http/tests/inspector/network/x-frame-options-deny.html [ Failure ] # Console error messages are wrongly ordered. @@ -30,7 +28,7 @@ # https://crbug.com/625765: Need to solve duplicate output from # WebFrameTestClient::willSendRequest() that causes text failures. -crbug.com/625765 http/tests/loading/redirect-methods.html [ Crash Failure ] +#crbug.com/625765 http/tests/loading/redirect-methods.html [ Crash Failure ] crbug.com/625765 virtual/mojo-loading/http/tests/loading/redirect-methods.html [ Crash Failure ] # https://crbug.com/555418: Move `X-Frame-Options` and CSP's `frame-ancestor` @@ -56,31 +54,8 @@ # https://crbug.com/638900: Failing due to flipped order of callbacks to # WebFrameClient::didStartProvisionalLoad() and # WebFrameClient::didFinishDocumentLoad(). -crbug.com/638900 fast/loader/subframe-removes-itself.html [ Failure ] -crbug.com/638900 http/tests/loading/css-no-cache-revalidation.html [ Failure ] crbug.com/638900 http/tests/loading/doc-write-sync-third-party-script-reload.html [ Failure ] -crbug.com/638900 http/tests/loading/image-picture-download-after-shrink.html [ Failure ] -crbug.com/638900 http/tests/loading/image-picture-no-download-after-picture-removal.html [ Failure ] -crbug.com/638900 http/tests/loading/image-picture-no-download-after-removal.html [ Failure ] -crbug.com/638900 http/tests/loading/image-picture-no-download-after-source-removal.html [ Failure ] -crbug.com/638900 http/tests/loading/redirect-with-no-location-crash.html [ Failure ] -crbug.com/638900 http/tests/loading/simple-subframe.html [ Failure ] -crbug.com/638900 http/tests/loading/slow-parsing-subframe.html [ Failure ] -crbug.com/638900 http/tests/navigation/cross-origin-fragment-navigation-is-async.html [ Failure ] -crbug.com/638900 http/tests/navigation/same-origin-fragment-navigation-is-sync.html [ Failure ] -crbug.com/638900 virtual/stable/http/tests/navigation/cross-origin-fragment-navigation-is-async.html [ Failure ] -crbug.com/638900 virtual/stable/http/tests/navigation/same-origin-fragment-navigation-is-sync.html [ Failure ] -crbug.com/638900 virtual/mojo-loading/http/tests/loading/css-no-cache-revalidation.html [ Failure ] crbug.com/638900 virtual/mojo-loading/http/tests/loading/doc-write-sync-third-party-script-reload.html [ Failure ] -crbug.com/638900 virtual/mojo-loading/http/tests/loading/image-picture-download-after-shrink.html [ Failure ] -crbug.com/638900 virtual/mojo-loading/http/tests/loading/image-picture-no-download-after-picture-removal.html [ Failure ] -crbug.com/638900 virtual/mojo-loading/http/tests/loading/image-picture-no-download-after-removal.html [ Failure ] -crbug.com/638900 virtual/mojo-loading/http/tests/loading/image-picture-no-download-after-source-removal.html [ Failure ] -crbug.com/638900 virtual/mojo-loading/http/tests/loading/redirect-with-no-location-crash.html [ Failure ] -crbug.com/638900 virtual/mojo-loading/http/tests/loading/simple-subframe.html [ Failure ] -crbug.com/638900 virtual/mojo-loading/http/tests/loading/slow-parsing-subframe.html [ Failure ] -crbug.com/638900 virtual/mojo-loading/http/tests/navigation/cross-origin-fragment-navigation-is-async.html [ Failure ] -crbug.com/638900 virtual/mojo-loading/http/tests/navigation/same-origin-fragment-navigation-is-sync.html [ Failure ] # https://crbug.com/640631: Failing due to difference in WebFrameClient # callback sequence on renderer-initiated failed navigations. @@ -110,7 +85,6 @@ crbug.com/689153 virtual/mojo-loading/http/tests/navigation/response204.html [ Timeout ] # This test seems to be partially failing without PlzNavigate as well. -Bug(none) external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects-exceptions.html [ Failure ] # These tests are flaky. Bug(none) http/tests/misc/window-open-then-write.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 index 85d3838..28604540 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -81,6 +81,7 @@ Bug(none) virtual/android/ [ Skip ] Bug(none) virtual/color_space/ [ Skip ] +Bug(none) virtual/disable-spinvalidation/ [ Skip ] Bug(none) virtual/display_list_2d_canvas/ [ Skip ] Bug(none) virtual/documentwriteevaluator/ [ Skip ] Bug(none) virtual/enable_asmjs/ [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process index 63483c4..81f62a3 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process +++ b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
@@ -157,10 +157,6 @@ crbug.com/24182 http/tests/perf/large-inlined-script.html [ Timeout Pass ] crbug.com/24182 virtual/mojo-loading/http/tests/perf/large-inlined-script.html [ Timeout Pass ] -# https://crbug.com/672570: autoplay-crossorigin.html fails w/ --site-per-process -crbug.com/672570 http/tests/media/autoplay-crossorigin.html [ Timeout ] -crbug.com/672570 virtual/mojo-loading/http/tests/media/autoplay-crossorigin.html [ Timeout ] - # https://crbug.com/680201: referrer-policy-attribute-import-no-referrer.html fails w/ --site-per-process crbug.com/680201 http/tests/security/referrer-policy-attribute-import-no-referrer.html [ Failure ] crbug.com/680201 virtual/mojo-loading/http/tests/security/referrer-policy-attribute-import-no-referrer.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 2ea282be..f93a7bd3 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -126,12 +126,7 @@ crbug.com/659192 virtual/gpu/fast/canvas/canvas-imageSmoothingQuality-pixel.html [ NeedsManualRebaseline ] -crbug.com/663838 fast/canvas/canvas-drawImage-live-video.html [ Pass Failure ] - -crbug.com/664846 paint/invalidation/background-resize-height.html [ Pass Failure ] - crbug.com/664850 virtual/display_list_2d_canvas/fast/canvas/canvas-createImageBitmap-webgl.html [ Pass Failure ] -crbug.com/664850 virtual/display_list_2d_canvas/fast/canvas/canvas-drawImage-live-video.html [ Pass Failure ] crbug.com/664850 virtual/display_list_2d_canvas/fast/canvas/OffscreenCanvas-2d-drawImage.html [ Pass Failure ] crbug.com/664850 virtual/display_list_2d_canvas/fast/canvas/OffscreenCanvas-commit-invalid-call.html [ Pass Failure ] crbug.com/664852 virtual/gpu/fast/canvas/canvas-createImageBitmap-webgl.html [ Pass Failure ] @@ -146,17 +141,21 @@ # Added 2016-12-15 crbug.com/674468 [ Trusty ] compositing/reflections/nested-reflection-transition.html [ Pass Failure ] +# Added 2017-01-16 +crbug.com/681471 paint/invalidation/media-audio-no-spurious-repaints.html [ Failure Pass Timeout ] +crbug.com/681471 virtual/disable-spinvalidation/paint/invalidation/media-audio-no-spurious-repaints.html [ Failure Pass Timeout ] + +# ====== Paint team owned tests to here ====== # ====== LayoutNG-only failures from here ====== # LayoutNG - is a new layout system for Blink. -# TODO(glebl): remove once new float/margin collapsing algorithm checked in. - - #### css2.1/20110323 -#### Passed: 112 -#### Skipped: 297 +#### Passed: 110 +#### Skipped: 299 crbug.com/635619 virtual/layout_ng/css2.1/20110323/absolute-non-replaced-height-002.htm [ Skip ] +crbug.com/635619 virtual/layout_ng/css2.1/20110323/floats-zero-height-wrap-001.htm [ Skip ] +crbug.com/635619 virtual/layout_ng/css2.1/20110323/floats-zero-height-wrap-002.htm [ Skip ] crbug.com/635619 virtual/layout_ng/css2.1/20110323/absolute-non-replaced-height-003.htm [ Skip ] crbug.com/635619 virtual/layout_ng/css2.1/20110323/absolute-non-replaced-height-004.htm [ Skip ] crbug.com/635619 virtual/layout_ng/css2.1/20110323/absolute-non-replaced-height-005.htm [ Skip ] @@ -455,8 +454,9 @@ crbug.com/635619 virtual/layout_ng/css2.1/20110323/width-replaced-element-001.htm [ Skip ] #### fast/block/basic -#### Passed: 3 -#### Skipped: 29 +#### Passed: 2 +#### Skipped: 30 +crbug.com/635619 virtual/layout_ng/fast/block/float/floats-not-cleared-crash.html [ Skip ] crbug.com/635619 virtual/layout_ng/fast/block/basic/001.html [ Skip ] crbug.com/635619 virtual/layout_ng/fast/block/basic/002.html [ Skip ] crbug.com/635619 virtual/layout_ng/fast/block/basic/003.html [ Skip ] @@ -817,7 +817,6 @@ crbug.com/518883 crbug.com/390452 virtual/mojo-loading/http/tests/security/isolatedWorld/media-query-wrapper-leaks.html [ Failure Pass Timeout ] crbug.com/518987 http/tests/xmlhttprequest/navigation-abort-detaches-frame.html [ Pass Timeout ] crbug.com/518989 [ Mac ] external/csswg-test/css-writing-modes-3/writing-mode-vertical-rl-002.xht [ Failure Pass Timeout ] -crbug.com/673296 [ Android ] inspector-protocol/input/dispatchMouseEvent.html [ Pass Timeout ] # These performance-sensitive user-timing tests are flaky in debug on all platforms, and flaky on all configurations of windows. # See: crbug.com/567965, crbug.com/518992, and crbug.com/518993 @@ -863,12 +862,10 @@ crbug.com/569139 fast/js/regexp-caching.html [ Failure ] crbug.com/597221 fast/dom/Window/window-postmessage-clone-deep-array.html [ Failure ] crbug.com/498539 [ Win ] inspector/tracing/decode-resize.html [ Failure Timeout ] -crbug.com/498539 inspector/console/console-log-syntax-error.html [ Pass Timeout ] crbug.com/498539 inspector/tracing/timeline-misc/timeline-bound-function.html [ Pass Failure ] crbug.com/498539 virtual/threaded/inspector/tracing/timeline-misc/timeline-bound-function.html [ Pass Failure ] crbug.com/498539 [ Mac ] inspector/sources/debugger/live-edit-no-reveal.html [ Crash Pass Timeout ] crbug.com/498539 [ Win7 ] inspector/sources/debugger-pause/debugger-eval-on-call-frame-inside-iframe.html [ Failure Pass ] -crbug.com/498539 [ Mac10.9 ] inspector/console/console-uncaught-exception.html [ Failure Pass ] crbug.com/498539 [ Win7 ] inspector/elements/styles-4/styles-update-from-js.html [ Crash Pass ] @@ -953,7 +950,6 @@ # MANIFEST.json contains any *-manual.*. https://github.com/w3c/web-platform-tests/issues/4137 Bug(github) external/wpt/uievents/keyboard/key-manual.css [ Skip ] Bug(github) external/wpt/uievents/keyboard/key-manual.js [ Skip ] -crbug.com/441355 external/wpt/dom/nodes/MutationObserver-childList.html [ Skip ] crbug.com/387740 external/wpt/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-audio-is-silence.https.html [ Skip ] crbug.com/387740 external/wpt/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https.html [ Skip ] @@ -1234,45 +1230,6 @@ crbug.com/381684 [ Mac Win ] fonts/family-fallback-gardiner.html [ Skip ] crbug.com/467635 fast/dom/HTMLImageElement/image-sizes-meta-viewport.html [ Skip ] -crbug.com/667966 virtual/android/fullscreen/video-controls-timeline.html [ NeedsRebaseline ] -crbug.com/667966 compositing/geometry/video-opacity-overlay.html [ NeedsRebaseline ] -crbug.com/667966 fast/borders/border-radius-mask-video-shadow.html [ NeedsRebaseline ] -crbug.com/667966 fast/borders/border-radius-mask-video-ratio.html [ NeedsRebaseline ] -crbug.com/667966 [ Android Mac Linux Win10 ] media/video-zoom-controls.html [ NeedsRebaseline ] -crbug.com/667966 virtual/android/fullscreen/full-screen-iframe-allowed-video.html [ NeedsRebaseline ] -crbug.com/667966 media/video-overlay-cast-dark-rendering.html [ NeedsRebaseline ] -crbug.com/667966 media/video-overlay-cast-light-rendering.html [ NeedsRebaseline ] -crbug.com/667966 compositing/video-frame-size-change.html [ NeedsRebaseline ] -crbug.com/667966 compositing/geometry/video-fixed-scrolling.html [ NeedsRebaseline ] -crbug.com/667966 fast/borders/border-radius-mask-video.html [ NeedsRebaseline ] -crbug.com/667966 virtual/android/fullscreen/video-scrolled-iframe.html [ NeedsRebaseline ] - -crbug.com/667966 media/video-aspect-ratio.html [ NeedsRebaseline ] -crbug.com/667966 compositing/video/video-reflection.html [ NeedsRebaseline ] -crbug.com/667966 media/track/track-cue-rendering-vertical.html [ NeedsRebaseline ] -crbug.com/667966 media/video-canvas-alpha.html [ NeedsRebaseline ] -crbug.com/667966 media/track/track-cue-rendering-horizontal.html [ NeedsRebaseline ] -crbug.com/667966 media/video-remove-insert-repaints.html [ NeedsRebaseline ] -crbug.com/667966 compositing/overflow/overflow-compositing-descendant.html [ NeedsRebaseline ] -crbug.com/667966 compositing/layers-inside-overflow-scroll.html [ NeedsRebaseline ] -crbug.com/667966 media/video-zoom.html [ NeedsRebaseline ] -crbug.com/667966 media/color-profile-video.html [ NeedsRebaseline ] -crbug.com/667966 compositing/self-painting-layers.html [ NeedsRebaseline ] -crbug.com/667966 compositing/overflow/scroll-ancestor-update.html [ NeedsRebaseline ] -crbug.com/667966 compositing/visibility/visibility-simple-video-layer.html [ NeedsRebaseline ] -crbug.com/667966 compositing/reflections/load-video-in-reflection.html [ NeedsRebaseline ] -crbug.com/667966 virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-compositing-descendant.html [ NeedsRebaseline ] -crbug.com/667966 media/video-replaces-poster.html [ NeedsRebaseline ] -crbug.com/667966 media/color-profile-video-seek-filter.html [ NeedsRebaseline ] -crbug.com/667966 media/color-profile-video-seek.html [ NeedsRebaseline ] -crbug.com/667966 media/color-profile-video-seek-object-fit.html [ NeedsRebaseline ] -crbug.com/667966 media/video-colorspace-yuv422.html [ NeedsRebaseline ] -crbug.com/667966 virtual/threaded/compositing/visibility/visibility-simple-video-layer.html [ NeedsRebaseline ] -crbug.com/667966 media/video-colorspace-yuv420.html [ NeedsRebaseline ] -crbug.com/667966 virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-ancestor-update.html [ NeedsRebaseline ] -crbug.com/667966 [ Mac Linux Android Win7 ] media/video-transformed.html [ NeedsRebaseline ] -crbug.com/667966 [ Mac Linux Android Win7 ] media/video-layer-crash.html [ NeedsRebaseline ] - crbug.com/636239 [ Win7 ] media/video-zoom-controls.html [ Failure ] @@ -1283,68 +1240,31 @@ crbug.com/474987 [ Win Mac ] css3/flexbox/auto-margins.html [ Failure ] crbug.com/658305 css3/filters/buffer-offset.html [ Failure Pass ] -crbug.com/658305 css3/filters/bug419429.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-all-on-background.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-all-on-background-hw.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-after.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-colorspace.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-colorspace-hw.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-composite.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-composite-hw.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-convolve-error.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-delete-crash.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-delete.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-displacement-negative-scale.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-external.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-external-stylesheet.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-hidpi.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-hidpi-hw.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-hw.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-image.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-image-hw.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-image-lazy-attach.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-lighting-no-light.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-local-url-with-base.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-merge-no-inputs.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-obb-dimensions.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-on-span-crash.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-on-transparent-element.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-ordering.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-ordering-hw.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-removed-while-pending-resources.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-rename-2.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-rename.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-reset-style-delete-crash.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-source-alpha-hw.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-subregion-chained.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-subregion-chained-hw.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-subregion-colormatrix.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-subregion-hidpi.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-subregion-hidpi-hw.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-subregion.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-subregion-hw.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-subregion-nested.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-subregion-zoom.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-subregion-zoom-hw.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-tile.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-tile-hw.html [ Failure Pass ] -crbug.com/658305 css3/filters/effect-reference-turbulence-invalid.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-zoom.html [ Failure Pass ] crbug.com/658305 css3/filters/effect-reference-zoom-hw.html [ Failure Pass ] -crbug.com/658305 css3/filters/empty-element-with-filter.html [ Failure Pass ] -crbug.com/658305 css3/filters/fecomposite-non-zero-inoffset.html [ Failure Pass ] -crbug.com/658305 css3/filters/feoffset-region-zoom.html [ Failure Pass ] crbug.com/658305 css3/filters/filter-effect-removed.html [ Failure Pass ] -crbug.com/658305 css3/filters/filter-region-negative-transformed-child.html [ Failure Pass ] -crbug.com/658305 css3/filters/filterRegions.html [ Failure Pass ] -crbug.com/658305 css3/filters/filter-region-transformed-child.html [ Failure Pass ] -crbug.com/658305 css3/filters/filter-region-transformed-composited-child.html [ Failure Pass ] -crbug.com/658305 css3/filters/filter-repaint-feimage.html [ Failure Pass ] -crbug.com/658305 css3/filters/filter-repaint-turbulence.html [ Failure Pass ] -crbug.com/658305 css3/filters/multiple-references-id-mutate-crash-2.html [ Failure Pass ] -crbug.com/658305 css3/filters/multiple-references-id-mutate-crash.html [ Failure Pass ] -crbug.com/658305 css3/filters/reference-filter-update-on-attribute-change.html [ Failure Pass ] crbug.com/267206 [ Mac ] fast/scrolling/scrollbar-tickmarks-hittest.html [ Timeout ] crbug.com/267206 [ Mac ] virtual/scroll_customization/fast/scrolling/scrollbar-tickmarks-hittest.html [ Timeout ] @@ -1469,7 +1389,9 @@ crbug.com/662010 [ Win7 ] csspaint/invalidation-background-image.html [ Skip ] # These tests are skipped as there is no touch support on Mac. +crbug.com/613672 [ Mac ] fast/events/pointerevents/multi-pointer-event-in-slop-region.html [ Skip ] crbug.com/613672 [ Mac ] fast/events/pointerevents/pointerevent_touch-action-pinch_zoom_touch.html [ Skip ] +crbug.com/613672 [ Mac ] fast/events/pointerevents/pointer-event-in-slop-region.html [ Skip ] crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_attributes_nohover_pointers-manual.html [ Skip ] crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_change-touch-action-onpointerdown_touch-manual.html [ Skip ] crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_pointerleave_after_pointercancel_touch-manual.html [ Skip ] @@ -1631,8 +1553,8 @@ crbug.com/479533 accessibility/show-context-menu-shadowdom.html [ Skip ] crbug.com/483653 accessibility/scroll-containers.html [ Skip ] -crbug.com/491764 http/tests/inspector/service-workers/user-agent-override.html [ Pass Failure Crash ] -crbug.com/491764 virtual/mojo-loading/http/tests/inspector/service-workers/user-agent-override.html [ Pass Failure ] +crbug.com/491764 http/tests/inspector/service-workers/user-agent-override.html [ Pass Timeout ] +crbug.com/491764 virtual/mojo-loading/http/tests/inspector/service-workers/user-agent-override.html [ Pass Timeout ] # expected.txt has weird chars that rietveld doesn't handle; will land it manually. crbug.com/660581 fast/dom/HTMLTableColElement/span-attribute.html [ Failure ] @@ -1731,12 +1653,6 @@ crbug.com/527270 accessibility/name-calc-img.html [ Failure Pass Timeout ] -crbug.com/673632 fast/css-generated-content/dynamic-apply-after-for-inline.html [ Failure Pass ] -crbug.com/673632 fast/css/collapsed-whitespace-reattach-in-style-recalc.html [ Failure Pass ] -crbug.com/673632 fast/inline/reattach-inlines-in-anonymous-blocks-with-out-of-flow-siblings.html [ Failure Pass ] -crbug.com/673632 fast/layout/display-none-no-relayout.html [ Failure Pass ] -crbug.com/673632 fast/selectors/style-sharing-shadow.html [ Failure Pass ] - # Win7 does not support the needed DirectWrite APIs for font fallback crbug.com/459056 [ Win7 ] fast/text/font-fallback-win.html [ Failure ] @@ -1787,8 +1703,6 @@ crbug.com/564109 [ Win7 ] virtual/mojo-loading/http/tests/webfont/font-display.html [ Pass Failure ] crbug.com/564109 [ Win7 ] virtual/mojo-loading/http/tests/webfont/font-display-intervention.html [ Pass Failure ] -crbug.com/575766 http/tests/inspector/resource-tree/resource-tree-frame-add.html [ Timeout Pass ] -crbug.com/575766 virtual/mojo-loading/http/tests/inspector/resource-tree/resource-tree-frame-add.html [ Timeout Pass ] crbug.com/581468 http/tests/inspector/resource-tree/resource-tree-non-unique-url.html [ Pass Failure ] crbug.com/399951 http/tests/mime/javascript-mimetype-usecounters.html [ Pass Failure ] @@ -1828,7 +1742,6 @@ crbug.com/605525 [ Win ] http/tests/xmlhttprequest/redirect-cross-origin-post.html [ Failure Pass ] -crbug.com/600248 external/wpt/web-animations/interfaces/AnimationEffectTiming/endDelay.html [ Pass Failure ] crbug.com/600248 external/wpt/web-animations/interfaces/Animation/constructor.html [ Failure Timeout ] crbug.com/600248 external/wpt/web-animations/interfaces/Animation/finished.html [ Pass Failure ] crbug.com/600248 external/wpt/web-animations/interfaces/Animation/oncancel.html [ Pass Failure ] @@ -1847,7 +1760,6 @@ crbug.com/605059 [ Retina ] fast/text/international/rtl-negative-letter-spacing.html [ Failure ] crbug.com/610464 [ Linux Win7 Debug ] inspector/components/throttler.html [ Failure Pass ] - crbug.com/487344 paint/invalidation/video-paint-invalidation.html [ Failure ] crbug.com/487344 virtual/disable-spinvalidation/paint/invalidation/video-paint-invalidation.html [ Failure ] crbug.com/487344 [ Win ] compositing/video/video-controls-layer-creation.html [ Pass Failure ] @@ -2159,7 +2071,6 @@ crbug.com/508730 crbug.com/472300 external/wpt/html/semantics/embedded-content/media-elements/interfaces/TextTrack/removeCue.html [ Failure ] crbug.com/508730 external/wpt/html/semantics/embedded-content/media-elements/track/track-element/cloneNode.html [ Failure ] crbug.com/508730 external/wpt/html/browsers/browsing-the-web/read-media/pageload-image.html [ Failure ] -crbug.com/508730 external/wpt/html/browsers/browsing-the-web/read-media/pageload-video.html [ Failure ] crbug.com/508730 external/wpt/html/webappapis/scripting/processing-model-2/compile-error-data-url.html [ Failure ] crbug.com/508730 external/wpt/workers/data-url.html [ Failure ] @@ -2217,11 +2128,6 @@ crbug.com/667371 inspector/elements/styles-1/color-aware-property-value-edit.html [ Pass Failure ] -# Fail when run in random order. -crbug.com/666991 external/wpt/service-workers/cache-storage/window/cache-storage.https.html [ Pass Failure ] -crbug.com/666991 external/wpt/service-workers/cache-storage/worker/cache-storage.https.html [ Pass Failure ] -crbug.com/666991 external/wpt/service-workers/cache-storage/serviceworker/cache-storage.https.html [ Pass Failure ] - # Newly imported tests that time out. crbug.com/666993 external/wpt/html/webappapis/idle-callbacks/callback-idle-periods.html [ Timeout ] crbug.com/666993 external/wpt/html/webappapis/idle-callbacks/callback-timeout-with-raf.html [ Timeout ] @@ -2244,10 +2150,6 @@ crbug.com/660384 external/wpt/webmessaging/without-ports/001.html [ Failure ] crbug.com/673526 external/wpt/webmessaging/message-channels/close.html [ Failure ] -# Added 2016-12-06 -crbug.com/671618 http/tests/websocket/workers/worker-reload.html [ Pass Timeout ] -crbug.com/671618 virtual/mojo-loading/http/tests/websocket/workers/worker-reload.html [ Pass Timeout ] - # Added 2016-12-12 crbug.com/610835 http/tests/security/XFrameOptions/x-frame-options-deny-multiple-clients.html [ Failure Pass ] crbug.com/610835 virtual/mojo-loading/http/tests/security/XFrameOptions/x-frame-options-deny-multiple-clients.html [ Failure Pass ] @@ -2257,7 +2159,6 @@ # Added 2016-12-15 crbug.com/674466 [ Win10 ] fast/forms/select/menulist-appearance-rtl.html [ Pass Failure ] -crbug.com/674720 [ Debug Trusty ] http/tests/loading/preload-img-test.html [ Pass Failure ] # Added 2016-12-16 crbug.com/674858 [ Linux ] virtual/threaded/printing/offscreencanvas-2d-printing.html [ Pass Failure Crash ] @@ -2270,23 +2171,11 @@ # These tests are flaky when run in random order, which is the default on Linux & Mac since since 2016-12-16. crbug.com/663585 editing/pasteboard/data-transfer-items-image-png.html [ Pass Failure ] -crbug.com/663840 fast/events/click-anchor-blur-refocus-window.html [ Pass Failure ] -crbug.com/663840 fast/events/click-anchor-refocus-window.html [ Pass Failure ] -crbug.com/663840 fast/events/click-checkbox-refocus-window.html [ Pass Failure ] -crbug.com/663840 fast/events/click-focus-anchor-has-ring.html [ Pass Failure ] -crbug.com/663840 fast/events/click-focus-keydown-no-ring.html [ Pass Failure ] -crbug.com/663840 fast/events/click-focus-svganchor-has-ring.html [ Pass Failure ] -crbug.com/663840 fast/events/click-focus-svganchor-no-ring.html [ Pass Failure ] -crbug.com/663840 fast/events/click-svganchor-blur-refocus-window.html [ Pass Failure ] -crbug.com/663840 fast/events/click-svganchor-refocus-window.html [ Pass Failure ] # Possible duplicate of crbug.com/509025 # crbug.com/663847 fast/events/context-no-deselect.html [ Pass Failure ] -crbug.com/663848 fast/events/middleClickAutoscroll-panIcon.html [ Pass Failure ] crbug.com/652536 fast/events/mouse-cursor.html [ Pass Failure ] -crbug.com/663851 fast/events/onload-re-entry.html [ Pass Failure ] -crbug.com/663853 fast/scroll-behavior/main-frame-interrupted-scroll.html [ Pass Failure ] crbug.com/671478 fast/table/percent-height-replaced-content-in-cell.html [ Pass Failure ] crbug.com/663855 fast/text/ellipsis-ltr-text-in-rtl-flow-underline-composition.html [ Pass Failure ] crbug.com/663855 fast/text/ellipsis-rtl-text-in-ltr-flow.html [ Pass Failure ] @@ -2298,82 +2187,21 @@ crbug.com/663855 fast/text/ellipsis-stroked.html [ Pass Failure ] crbug.com/663858 fast/text/emphasis.html [ Pass Failure ] crbug.com/663858 fast/text/emphasis-vertical.html [ Pass Failure ] -crbug.com/663872 http/tests/fetch/serviceworker-proxied/thorough/cookie-nocors.html [ Pass Failure ] -crbug.com/663872 http/tests/fetch/serviceworker-proxied/thorough/cors-preflight-other-https.html [ Pass Failure ] -crbug.com/663872 http/tests/fetch/serviceworker-proxied/thorough/redirect-base-https-other-https.html [ Pass Failure ] -crbug.com/663872 http/tests/fetch/serviceworker-proxied/thorough/redirect-credentials-base-https-other-https.html [ Pass Failure ] -crbug.com/663874 http/tests/fetch/window/thorough/access-control-base-https-other-https.html [ Pass Failure ] -crbug.com/663874 http/tests/fetch/window/thorough/access-control.html [ Pass Failure ] -crbug.com/663874 http/tests/fetch/window/thorough/auth-base-https-other-https.html [ Pass Failure ] -crbug.com/663874 http/tests/fetch/window/thorough/auth.html [ Pass Failure ] -crbug.com/663874 http/tests/fetch/window/thorough/auth-other-https.html [ Pass Failure ] -crbug.com/663874 http/tests/fetch/window/thorough/cookie-base-https-other-https.html [ Pass Failure ] -crbug.com/663874 http/tests/fetch/window/thorough/cookie-nocors-other-https.html [ Pass Failure ] -crbug.com/663874 http/tests/fetch/window/thorough/cors-preflight2-base-https-other-https.html [ Pass Failure ] -crbug.com/663874 http/tests/fetch/window/thorough/cors-preflight2-other-https.html [ Pass Failure ] -crbug.com/663874 http/tests/fetch/window/thorough/cors-preflight-base-https-other-https.html [ Pass Failure ] -crbug.com/663874 http/tests/fetch/window/thorough/redirect-base-https-other-https.html [ Pass Failure ] -crbug.com/663874 http/tests/fetch/window/thorough/redirect-password-other-https.html [ Pass Failure ] -crbug.com/663874 http/tests/fetch/window/thorough/scheme-blob.html [ Pass Failure ] -crbug.com/663874 http/tests/fetch/window/thorough/scheme-data-other-https.html [ Pass Failure ] -crbug.com/671480 http/tests/inspector/file-system-project-mapping.html [ Pass Failure ] crbug.com/663876 http/tests/loading/doc-write-sync-third-party-script-block-effectively-2g.html [ Pass Failure ] -crbug.com/663877 http/tests/media/video-load-suspend.html [ Pass Failure ] -crbug.com/663879 http/tests/misc/script-no-store.html [ Pass Failure ] crbug.com/664816 http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-reportonly-blocked.php [ Pass Failure ] -crbug.com/664817 http/tests/security/contentTypeOptions/block-image-as-script.html [ Pass Failure ] -crbug.com/664839 http/tests/security/cors-rfc1918/internal-to-internal-xhr.html [ Pass Failure ] -crbug.com/664839 http/tests/security/document-origin-domain.html [ Pass Failure ] crbug.com/664819 http/tests/security/isolatedWorld/bypass-main-world-csp-for-inline-style.html [ Pass Failure ] crbug.com/664819 http/tests/security/isolatedWorld/bypass-main-world-csp-for-xhr.html [ Pass Failure ] crbug.com/664819 http/tests/security/isolatedWorld/bypass-main-world-csp-iframes.html [ Pass Failure ] crbug.com/664819 http/tests/security/isolatedWorld/events.html [ Pass Failure ] crbug.com/664839 http/tests/security/link-crossorigin-preload-no-cors.html [ Pass Failure ] -crbug.com/664839 http/tests/security/same-origin-css.html [ Pass Failure ] -crbug.com/664839 http/tests/security/same-origin-css-in-quirks.html [ Pass Failure ] crbug.com/671475 http/tests/security/suborigins/suborigin-invalid-options.html [ Pass Failure ] -crbug.com/664839 http/tests/security/webgl-remote-read-remote-image-allowed.html [ Pass Failure ] -crbug.com/664839 http/tests/security/webgl-remote-read-remote-image-allowed-with-credentials.html [ Pass Failure ] -crbug.com/664840 http/tests/w3c/webperf/submission/Google/resource-timing/html/test_resource_script_types.html [ Pass Failure ] -crbug.com/664841 http/tests/workers/worker-document-domain-security.html [ Pass Failure ] -crbug.com/664841 http/tests/workers/worker-performance-timeline.html [ Pass Failure ] -crbug.com/663872 virtual/mojo-loading/http/tests/fetch/serviceworker-proxied/thorough/cookie-nocors.html [ Pass Failure ] -crbug.com/663872 virtual/mojo-loading/http/tests/fetch/serviceworker-proxied/thorough/cors-preflight-other-https.html [ Pass Failure ] -crbug.com/663872 virtual/mojo-loading/http/tests/fetch/serviceworker-proxied/thorough/redirect-base-https-other-https.html [ Pass Failure ] -crbug.com/663872 virtual/mojo-loading/http/tests/fetch/serviceworker-proxied/thorough/redirect-credentials-base-https-other-https.html [ Pass Failure ] -crbug.com/663874 virtual/mojo-loading/http/tests/fetch/window/thorough/access-control-base-https-other-https.html [ Pass Failure ] -crbug.com/663874 virtual/mojo-loading/http/tests/fetch/window/thorough/access-control.html [ Pass Failure ] -crbug.com/663874 virtual/mojo-loading/http/tests/fetch/window/thorough/auth-base-https-other-https.html [ Pass Failure ] -crbug.com/663874 virtual/mojo-loading/http/tests/fetch/window/thorough/auth.html [ Pass Failure ] -crbug.com/663874 virtual/mojo-loading/http/tests/fetch/window/thorough/auth-other-https.html [ Pass Failure ] -crbug.com/663874 virtual/mojo-loading/http/tests/fetch/window/thorough/cookie-base-https-other-https.html [ Pass Failure ] -crbug.com/663874 virtual/mojo-loading/http/tests/fetch/window/thorough/cookie-nocors-other-https.html [ Pass Failure ] -crbug.com/663874 virtual/mojo-loading/http/tests/fetch/window/thorough/cors-preflight2-base-https-other-https.html [ Pass Failure ] -crbug.com/663874 virtual/mojo-loading/http/tests/fetch/window/thorough/cors-preflight2-other-https.html [ Pass Failure ] -crbug.com/663874 virtual/mojo-loading/http/tests/fetch/window/thorough/cors-preflight-base-https-other-https.html [ Pass Failure ] -crbug.com/663874 virtual/mojo-loading/http/tests/fetch/window/thorough/redirect-base-https-other-https.html [ Pass Failure ] -crbug.com/663874 virtual/mojo-loading/http/tests/fetch/window/thorough/redirect-password-other-https.html [ Pass Failure ] -crbug.com/663874 virtual/mojo-loading/http/tests/fetch/window/thorough/scheme-blob.html [ Pass Failure ] -crbug.com/663874 virtual/mojo-loading/http/tests/fetch/window/thorough/scheme-data-other-https.html [ Pass Failure ] crbug.com/663876 virtual/mojo-loading/http/tests/loading/doc-write-sync-third-party-script-block-effectively-2g.html [ Pass Failure ] -crbug.com/663877 virtual/mojo-loading/http/tests/media/video-load-suspend.html [ Pass Failure ] -crbug.com/663879 virtual/mojo-loading/http/tests/misc/script-no-store.html [ Pass Failure ] crbug.com/664816 virtual/mojo-loading/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-reportonly-blocked.php [ Pass Failure ] -crbug.com/664817 virtual/mojo-loading/http/tests/security/contentTypeOptions/block-image-as-script.html [ Pass Failure ] -crbug.com/664839 virtual/mojo-loading/http/tests/security/cors-rfc1918/internal-to-internal-xhr.html [ Pass Failure ] -crbug.com/664839 virtual/mojo-loading/http/tests/security/document-origin-domain.html [ Pass Failure ] crbug.com/664819 virtual/mojo-loading/http/tests/security/isolatedWorld/bypass-main-world-csp-for-inline-style.html [ Pass Failure ] crbug.com/664819 virtual/mojo-loading/http/tests/security/isolatedWorld/bypass-main-world-csp-for-xhr.html [ Pass Failure ] crbug.com/664819 virtual/mojo-loading/http/tests/security/isolatedWorld/bypass-main-world-csp-iframes.html [ Pass Failure ] crbug.com/664819 virtual/mojo-loading/http/tests/security/isolatedWorld/events.html [ Pass Failure ] crbug.com/664839 virtual/mojo-loading/http/tests/security/link-crossorigin-preload-no-cors.html [ Pass Failure ] -crbug.com/664839 virtual/mojo-loading/http/tests/security/same-origin-css.html [ Pass Failure ] -crbug.com/664839 virtual/mojo-loading/http/tests/security/same-origin-css-in-quirks.html [ Pass Failure ] -crbug.com/664839 virtual/mojo-loading/http/tests/security/webgl-remote-read-remote-image-allowed.html [ Pass Failure ] -crbug.com/664839 virtual/mojo-loading/http/tests/security/webgl-remote-read-remote-image-allowed-with-credentials.html [ Pass Failure ] -crbug.com/664840 virtual/mojo-loading/http/tests/w3c/webperf/submission/Google/resource-timing/html/test_resource_script_types.html [ Pass Failure ] -crbug.com/664841 virtual/mojo-loading/http/tests/workers/worker-document-domain-security.html [ Pass Failure ] -crbug.com/664841 virtual/mojo-loading/http/tests/workers/worker-performance-timeline.html [ Pass Failure ] crbug.com/686478 fast/text/ellipsis-with-list-marker-in-ltr-flow.html [ Pass Failure ] crbug.com/686478 fast/text/ellipsis-with-list-marker-in-rtl-flow.html [ Pass Failure ] @@ -2381,13 +2209,11 @@ # Possible duplicate of crbug.com/498539 # crbug.com/664843 inspector/elements/styles-4/styles-update-from-js.html [ Pass Failure ] -crbug.com/664842 inspector-protocol/heap-profiler/heap-snapshot-with-active-dom-object.html [ Pass Failure ] -crbug.com/672204 media/avtrack/video-track-selected.html [ Pass Failure ] crbug.com/664844 media/track/track-cue-rendering-tree-is-removed-properly.html [ Pass Failure ] crbug.com/664844 media/track/track-default-attribute.html [ Pass Failure ] crbug.com/664844 media/track/track-kind-user-preference.html [ Pass Failure ] -crbug.com/664855 virtual/scroll_customization/fast/scroll-behavior/main-frame-interrupted-scroll.html [ Pass Failure ] -crbug.com/664856 virtual/sharedarraybuffer/fast/workers/worker-gc.html [ Pass Failure ] + +crbug.com/688670 media/track/track-cue-rendering-after-controls-removed.html [ Pass Failure ] # Possible duplicate of crbug.com/665577 # crbug.com/664858 virtual/threaded/fast/scroll-behavior/overflow-scroll-animates.html [ Pass Failure ] @@ -2444,7 +2270,6 @@ crbug.com/678487 http/tests/inspector/resource-tree/resource-tree-reload.html [ Failure Timeout Pass ] crbug.com/678487 virtual/mojo-loading/http/tests/inspector/resource-tree/resource-tree-reload.html [ Failure Timeout Pass ] crbug.com/678488 http/tests/inspector/search/source-frame-replace-2.html [ Timeout Pass ] -crbug.com/678488 virtual/mojo-loading/http/tests/inspector/search/source-frame-replace-2.html [ Timeout Pass ] crbug.com/678489 http/tests/inspector/tracing/timeline-script-parse.html [ Timeout Pass ] crbug.com/678489 virtual/mojo-loading/http/tests/inspector/tracing/timeline-script-parse.html [ Timeout Pass ] crbug.com/678490 http/tests/media/media-source/mediasource-seek-beyond-duration.html [ Failure Pass ] @@ -2458,15 +2283,13 @@ crbug.com/680050 inspector/sources/debugger-ui/watch-expressions-panel-switch.html [ Pass Timeout ] +crbug.com/689781 http/tests/media/media-source/mediasource-duration.html [ Failure Pass ] + # When WebAssembly is exposed in V8 (soon), this test has the wrong number of expected Object.getOwnPropertyNames() for global object. -crbug.com/575167 external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects-exceptions.html [ NeedsManualRebaseline ] crbug.com/681468 fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom125.html [ Failure Pass ] crbug.com/681468 fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom200.html [ Failure Pass ] -crbug.com/681471 paint/invalidation/media-audio-no-spurious-repaints.html [ Failure Pass Timeout ] -crbug.com/681471 virtual/disable-spinvalidation/paint/invalidation/media-audio-no-spurious-repaints.html [ Failure Pass Timeout ] - crbug.com/683800 [ Win7 Debug ] external/wpt/selection/ [ Failure Pass ] # CQ and Rebaseline-cl for crrev.com/2626973005 does not include this
diff --git a/third_party/WebKit/LayoutTests/W3CImportExpectations b/third_party/WebKit/LayoutTests/W3CImportExpectations index d8eb254..09017faf 100644 --- a/third_party/WebKit/LayoutTests/W3CImportExpectations +++ b/third_party/WebKit/LayoutTests/W3CImportExpectations
@@ -304,6 +304,8 @@ ## Owners: mkwst@chromium.org # http://crbug.com/360762: Requires HTTPS server with python. external/wpt/referrer-policy [ Skip ] +## Owners: avayvod@chromium.org,mlamouri@chromium.org +# external/wpt/remote-playback [ Pass ] external/wpt/resource-timing [ Skip ] ## Owners: jsbell@chromium.org # external/wpt/resources [ Pass ]
diff --git a/third_party/WebKit/LayoutTests/accessibility/readme.md b/third_party/WebKit/LayoutTests/accessibility/readme.md new file mode 100644 index 0000000..ab9236d7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/accessibility/readme.md
@@ -0,0 +1,25 @@ +# LayoutTests for Accessibility + +## General Info on LayoutTests: Building and Running the Tests + +See https://chromium.googlesource.com/chromium/src/+/master/docs/testing/layout_tests.md for general info on how to build and run LayoutTests. + +## Old vs. New + +There are two styles of accessibility layout tests: +* Using a ```-expected.txt``` (now deprecated) +* Unit-style tests with assertions + +Use the unit-style tests. An example is aria-modal.html. + +## Methodology and Bindings + +These tests check the accessibility tree directly in Blink using ```AccessibilityController```, which is just a test helper. + +The code that implements the bindings is here: + +* ```components/test_runner/accessibility_controller.cc``` +* ```components/test_runner/web_ax_object_proxy.cc``` + +You'll probably find bindings for the features you want to test already. If not, it's not hard to add new ones. +
diff --git a/third_party/WebKit/LayoutTests/animations/composition/rotate-composition.html b/third_party/WebKit/LayoutTests/animations/composition/rotate-composition.html index 82dd457..ae01bc3 100644 --- a/third_party/WebKit/LayoutTests/animations/composition/rotate-composition.html +++ b/third_party/WebKit/LayoutTests/animations/composition/rotate-composition.html
@@ -99,4 +99,60 @@ {at: 1, is: '90deg'}, {at: 2, is: '-6.12323e-17 -1 -4.71028e-16 90deg'}, ]); + +assertComposition({ + property: 'rotate', + underlying: 'none', + addFrom: 'none', + replaceTo: '0 1 0 100deg', +}, [ + {at: -1, is: '0 1 0 -100deg'}, + {at: 0, is: '0deg'}, + {at: 0.25, is: '-1.20172e-16 1 -3.60516e-16 25deg'}, + {at: 0.75, is: '-1.51909e-17 1 -4.55726e-17 75deg'}, + {at: 1, is: '0 1 0 100deg'}, + {at: 2, is: '0 1 0 200deg'}, +]); + +assertComposition({ + property: 'rotate', + underlying: 'none', + addFrom: '2 4 6 270deg', + replaceTo: 'none', +}, [ + {at: -1, is: '2 4 6 540deg'}, + {at: 0, is: '2 4 6 270deg'}, + {at: 0.25, is: '2 4 6 202.5deg'}, + {at: 0.75, is: '2 4 6 67.5deg'}, + {at: 1, is: '0deg'}, + {at: 2, is: '2 4 6 -270deg'}, +]); + +assertComposition({ + property: 'rotate', + underlying: '1 2 3 90deg', + addFrom: 'none', + replaceTo: '0 1 0 100deg', +}, [ + {at: -1, is: '0.31 -0.22 0.92 131.66deg'}, + {at: 0, is: '1 2 3 90deg'}, + {at: 0.25, is: '0.21 0.73 0.64 86.72deg'}, + {at: 0.75, is: '0.07 0.97 0.21 92.05deg'}, + {at: 1, is: '0 1 0 100deg'}, + {at: 2, is: '-0.2 0.79 -0.59 151.11deg'}, +]); + +assertComposition({ + property: 'rotate', + underlying: '1 2 3 90deg', + addFrom: '2 4 6 270deg', + replaceTo: 'none', +}, [ + {at: -1, is: '1 2 3 720deg'}, + {at: 0, is: '1 2 3 360deg'}, + {at: 0.25, is: '1 2 3 270deg'}, + {at: 0.75, is: '1 2 3 90deg'}, + {at: 1, is: '0deg'}, + {at: 2, is: '1 2 3 -360deg'}, +]); </script>
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/rotate-interpolation-expected.txt b/third_party/WebKit/LayoutTests/animations/interpolation/rotate-interpolation-expected.txt new file mode 100644 index 0000000..7d1b36c --- /dev/null +++ b/third_party/WebKit/LayoutTests/animations/interpolation/rotate-interpolation-expected.txt
@@ -0,0 +1,202 @@ +This is a testharness.js-based test. +PASS This test uses interpolation-test.js. +PASS CSS Transitions: property <rotate> from [none] to [30deg] at (-1) is [-30deg] +PASS CSS Transitions: property <rotate> from [none] to [30deg] at (0) is [none] +PASS CSS Transitions: property <rotate> from [none] to [30deg] at (0.25) is [7.5deg] +PASS CSS Transitions: property <rotate> from [none] to [30deg] at (0.75) is [22.5deg] +PASS CSS Transitions: property <rotate> from [none] to [30deg] at (1) is [30deg] +PASS CSS Transitions: property <rotate> from [none] to [30deg] at (2) is [60deg] +PASS CSS Transitions: property <rotate> from neutral to [30deg] at (-1) is [-10deg] +PASS CSS Transitions: property <rotate> from neutral to [30deg] at (0) is [10deg] +PASS CSS Transitions: property <rotate> from neutral to [30deg] at (0.25) is [15deg] +PASS CSS Transitions: property <rotate> from neutral to [30deg] at (0.75) is [25deg] +PASS CSS Transitions: property <rotate> from neutral to [30deg] at (1) is [30deg] +PASS CSS Transitions: property <rotate> from neutral to [30deg] at (2) is [50deg] +PASS CSS Transitions: property <rotate> from [unset] to [30deg] at (-1) is [-30deg] +PASS CSS Transitions: property <rotate> from [unset] to [30deg] at (0) is [none] +PASS CSS Transitions: property <rotate> from [unset] to [30deg] at (0.25) is [7.5deg] +PASS CSS Transitions: property <rotate> from [unset] to [30deg] at (0.75) is [22.5deg] +PASS CSS Transitions: property <rotate> from [unset] to [30deg] at (1) is [30deg] +PASS CSS Transitions: property <rotate> from [unset] to [30deg] at (2) is [60deg] +PASS CSS Transitions: property <rotate> from [100deg] to [-100deg] at (-1) is [300deg] +PASS CSS Transitions: property <rotate> from [100deg] to [-100deg] at (0) is [100deg] +PASS CSS Transitions: property <rotate> from [100deg] to [-100deg] at (0.25) is [50deg] +PASS CSS Transitions: property <rotate> from [100deg] to [-100deg] at (0.75) is [-50deg] +PASS CSS Transitions: property <rotate> from [100deg] to [-100deg] at (1) is [-100deg] +PASS CSS Transitions: property <rotate> from [100deg] to [-100deg] at (2) is [-300deg] +PASS CSS Transitions: property <rotate> from [100deg] to [-100deg] at (-1) is [300deg] +PASS CSS Transitions: property <rotate> from [100deg] to [-100deg] at (0) is [100deg] +PASS CSS Transitions: property <rotate> from [100deg] to [-100deg] at (0.25) is [50deg] +PASS CSS Transitions: property <rotate> from [100deg] to [-100deg] at (0.75) is [-50deg] +PASS CSS Transitions: property <rotate> from [100deg] to [-100deg] at (1) is [-100deg] +PASS CSS Transitions: property <rotate> from [100deg] to [-100deg] at (2) is [-300deg] +PASS CSS Transitions: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (-1) is [0 1 0 300deg] +PASS CSS Transitions: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (0) is [0 1 0 100deg] +PASS CSS Transitions: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (0.25) is [0 1 0 50deg] +PASS CSS Transitions: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (0.75) is [0 1 0 -50deg] +PASS CSS Transitions: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (1) is [0 1 0 -100deg] +PASS CSS Transitions: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (2) is [0 1 0 -300deg] +PASS CSS Transitions: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (-1) is [1 -2.5 3.64 300deg] +PASS CSS Transitions: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (0) is [1 -2.5 3.64 100deg] +PASS CSS Transitions: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (0.25) is [1 -2.5 3.64 50deg] +PASS CSS Transitions: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (0.75) is [1 -2.5 3.64 -50deg] +PASS CSS Transitions: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (1) is [1 -2.5 3.64 -100deg] +PASS CSS Transitions: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (2) is [1 -2.5 3.64 -300deg] +PASS CSS Transitions: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (-1) is [0 1 0 -10deg] +PASS CSS Transitions: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (0) is [1 0 0 0deg] +PASS CSS Transitions: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (0.25) is [0 1 0 2.5deg] +PASS CSS Transitions: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (0.75) is [0 1 0 7.5deg] +PASS CSS Transitions: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (1) is [0 1 0 10deg] +PASS CSS Transitions: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (2) is [0 1 0 20deg] +PASS CSS Transitions: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (-1) is [0.673392 -0.0631886 -0.73658 124.975deg] +PASS CSS Transitions: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (0) is [1 1 0 90deg] +PASS CSS Transitions: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (0.25) is [0.544172 0.799255 0.255083 94.834deg] +PASS CSS Transitions: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (0.75) is [0.167111 0.775694 0.608583 118.679deg] +PASS CSS Transitions: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (1) is [0 1 1 135deg] +PASS CSS Transitions: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (2) is [0.516398 -0.289524 -0.805921 151.045deg] +PASS CSS Transitions: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (-1) is [1 0 0 -450deg] +PASS CSS Transitions: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (0) is [0 1 0 0deg] +PASS CSS Transitions: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (0.25) is [1 0 0 112.5deg] +PASS CSS Transitions: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (0.75) is [1 0 0 337.5deg] +PASS CSS Transitions: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (1) is [1 0 0 450deg] +PASS CSS Transitions: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (2) is [1 0 0 900deg] +PASS CSS Transitions: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (-1) is [1 0 0 900deg] +PASS CSS Transitions: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (0) is [1 0 0 450deg] +PASS CSS Transitions: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (0.25) is [1 0 0 337.5deg] +PASS CSS Transitions: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (0.75) is [1 0 0 112.5deg] +PASS CSS Transitions: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (1) is [0 1 0 0deg] +PASS CSS Transitions: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (2) is [1 0 0 -450deg] +PASS CSS Animations: property <rotate> from [none] to [30deg] at (-1) is [-30deg] +FAIL CSS Animations: property <rotate> from [none] to [30deg] at (0) is [0deg] assert_equals: expected "none " but got "0deg " +PASS CSS Animations: property <rotate> from [none] to [30deg] at (0.25) is [7.5deg] +PASS CSS Animations: property <rotate> from [none] to [30deg] at (0.75) is [22.5deg] +PASS CSS Animations: property <rotate> from [none] to [30deg] at (1) is [30deg] +PASS CSS Animations: property <rotate> from [none] to [30deg] at (2) is [60deg] +PASS CSS Animations: property <rotate> from neutral to [30deg] at (-1) is [-10deg] +PASS CSS Animations: property <rotate> from neutral to [30deg] at (0) is [10deg] +PASS CSS Animations: property <rotate> from neutral to [30deg] at (0.25) is [15deg] +PASS CSS Animations: property <rotate> from neutral to [30deg] at (0.75) is [25deg] +PASS CSS Animations: property <rotate> from neutral to [30deg] at (1) is [30deg] +PASS CSS Animations: property <rotate> from neutral to [30deg] at (2) is [50deg] +PASS CSS Animations: property <rotate> from [unset] to [30deg] at (-1) is [-30deg] +FAIL CSS Animations: property <rotate> from [unset] to [30deg] at (0) is [0deg] assert_equals: expected "none " but got "0deg " +PASS CSS Animations: property <rotate> from [unset] to [30deg] at (0.25) is [7.5deg] +PASS CSS Animations: property <rotate> from [unset] to [30deg] at (0.75) is [22.5deg] +PASS CSS Animations: property <rotate> from [unset] to [30deg] at (1) is [30deg] +PASS CSS Animations: property <rotate> from [unset] to [30deg] at (2) is [60deg] +PASS CSS Animations: property <rotate> from [100deg] to [-100deg] at (-1) is [300deg] +PASS CSS Animations: property <rotate> from [100deg] to [-100deg] at (0) is [100deg] +PASS CSS Animations: property <rotate> from [100deg] to [-100deg] at (0.25) is [50deg] +PASS CSS Animations: property <rotate> from [100deg] to [-100deg] at (0.75) is [-50deg] +PASS CSS Animations: property <rotate> from [100deg] to [-100deg] at (1) is [-100deg] +PASS CSS Animations: property <rotate> from [100deg] to [-100deg] at (2) is [-300deg] +PASS CSS Animations: property <rotate> from [100deg] to [-100deg] at (-1) is [300deg] +PASS CSS Animations: property <rotate> from [100deg] to [-100deg] at (0) is [100deg] +PASS CSS Animations: property <rotate> from [100deg] to [-100deg] at (0.25) is [50deg] +PASS CSS Animations: property <rotate> from [100deg] to [-100deg] at (0.75) is [-50deg] +PASS CSS Animations: property <rotate> from [100deg] to [-100deg] at (1) is [-100deg] +PASS CSS Animations: property <rotate> from [100deg] to [-100deg] at (2) is [-300deg] +PASS CSS Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (-1) is [0 1 0 300deg] +PASS CSS Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (0) is [0 1 0 100deg] +PASS CSS Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (0.25) is [0 1 0 50deg] +PASS CSS Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (0.75) is [0 1 0 -50deg] +PASS CSS Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (1) is [0 1 0 -100deg] +PASS CSS Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (2) is [0 1 0 -300deg] +PASS CSS Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (-1) is [1 -2.5 3.64 300deg] +PASS CSS Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (0) is [1 -2.5 3.64 100deg] +PASS CSS Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (0.25) is [1 -2.5 3.64 50deg] +PASS CSS Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (0.75) is [1 -2.5 3.64 -50deg] +PASS CSS Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (1) is [1 -2.5 3.64 -100deg] +PASS CSS Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (2) is [1 -2.5 3.64 -300deg] +PASS CSS Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (-1) is [0 1 0 -10deg] +PASS CSS Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (0) is [1 0 0 0deg] +PASS CSS Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (0.25) is [0 1 0 2.5deg] +PASS CSS Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (0.75) is [0 1 0 7.5deg] +PASS CSS Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (1) is [0 1 0 10deg] +PASS CSS Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (2) is [0 1 0 20deg] +PASS CSS Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (-1) is [0.673392 -0.0631886 -0.73658 124.975deg] +PASS CSS Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (0) is [1 1 0 90deg] +PASS CSS Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (0.25) is [0.544172 0.799255 0.255083 94.834deg] +PASS CSS Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (0.75) is [0.167111 0.775694 0.608583 118.679deg] +PASS CSS Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (1) is [0 1 1 135deg] +PASS CSS Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (2) is [0.516398 -0.289524 -0.805921 151.045deg] +PASS CSS Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (-1) is [1 0 0 -450deg] +PASS CSS Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (0) is [0 1 0 0deg] +PASS CSS Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (0.25) is [1 0 0 112.5deg] +PASS CSS Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (0.75) is [1 0 0 337.5deg] +PASS CSS Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (1) is [1 0 0 450deg] +PASS CSS Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (2) is [1 0 0 900deg] +PASS CSS Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (-1) is [1 0 0 900deg] +PASS CSS Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (0) is [1 0 0 450deg] +PASS CSS Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (0.25) is [1 0 0 337.5deg] +PASS CSS Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (0.75) is [1 0 0 112.5deg] +PASS CSS Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (1) is [0 1 0 0deg] +PASS CSS Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (2) is [1 0 0 -450deg] +PASS Web Animations: property <rotate> from [none] to [30deg] at (-1) is [-30deg] +FAIL Web Animations: property <rotate> from [none] to [30deg] at (0) is [0deg] assert_equals: expected "none " but got "0deg " +PASS Web Animations: property <rotate> from [none] to [30deg] at (0.25) is [7.5deg] +PASS Web Animations: property <rotate> from [none] to [30deg] at (0.75) is [22.5deg] +PASS Web Animations: property <rotate> from [none] to [30deg] at (1) is [30deg] +PASS Web Animations: property <rotate> from [none] to [30deg] at (2) is [60deg] +PASS Web Animations: property <rotate> from neutral to [30deg] at (-1) is [-10deg] +PASS Web Animations: property <rotate> from neutral to [30deg] at (0) is [10deg] +PASS Web Animations: property <rotate> from neutral to [30deg] at (0.25) is [15deg] +PASS Web Animations: property <rotate> from neutral to [30deg] at (0.75) is [25deg] +PASS Web Animations: property <rotate> from neutral to [30deg] at (1) is [30deg] +PASS Web Animations: property <rotate> from neutral to [30deg] at (2) is [50deg] +PASS Web Animations: property <rotate> from [unset] to [30deg] at (-1) is [-30deg] +FAIL Web Animations: property <rotate> from [unset] to [30deg] at (0) is [0deg] assert_equals: expected "none " but got "0deg " +PASS Web Animations: property <rotate> from [unset] to [30deg] at (0.25) is [7.5deg] +PASS Web Animations: property <rotate> from [unset] to [30deg] at (0.75) is [22.5deg] +PASS Web Animations: property <rotate> from [unset] to [30deg] at (1) is [30deg] +PASS Web Animations: property <rotate> from [unset] to [30deg] at (2) is [60deg] +PASS Web Animations: property <rotate> from [100deg] to [-100deg] at (-1) is [300deg] +PASS Web Animations: property <rotate> from [100deg] to [-100deg] at (0) is [100deg] +PASS Web Animations: property <rotate> from [100deg] to [-100deg] at (0.25) is [50deg] +PASS Web Animations: property <rotate> from [100deg] to [-100deg] at (0.75) is [-50deg] +PASS Web Animations: property <rotate> from [100deg] to [-100deg] at (1) is [-100deg] +PASS Web Animations: property <rotate> from [100deg] to [-100deg] at (2) is [-300deg] +PASS Web Animations: property <rotate> from [100deg] to [-100deg] at (-1) is [300deg] +PASS Web Animations: property <rotate> from [100deg] to [-100deg] at (0) is [100deg] +PASS Web Animations: property <rotate> from [100deg] to [-100deg] at (0.25) is [50deg] +PASS Web Animations: property <rotate> from [100deg] to [-100deg] at (0.75) is [-50deg] +PASS Web Animations: property <rotate> from [100deg] to [-100deg] at (1) is [-100deg] +PASS Web Animations: property <rotate> from [100deg] to [-100deg] at (2) is [-300deg] +PASS Web Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (-1) is [0 1 0 300deg] +PASS Web Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (0) is [0 1 0 100deg] +PASS Web Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (0.25) is [0 1 0 50deg] +PASS Web Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (0.75) is [0 1 0 -50deg] +PASS Web Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (1) is [0 1 0 -100deg] +PASS Web Animations: property <rotate> from [0 1 0 100deg] to [0 1 0 -100deg] at (2) is [0 1 0 -300deg] +PASS Web Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (-1) is [1 -2.5 3.64 300deg] +PASS Web Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (0) is [1 -2.5 3.64 100deg] +PASS Web Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (0.25) is [1 -2.5 3.64 50deg] +PASS Web Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (0.75) is [1 -2.5 3.64 -50deg] +PASS Web Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (1) is [1 -2.5 3.64 -100deg] +PASS Web Animations: property <rotate> from [1 -2.5 3.64 100deg] to [1 -2.5 3.64 -100deg] at (2) is [1 -2.5 3.64 -300deg] +PASS Web Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (-1) is [0 1 0 -10deg] +PASS Web Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (0) is [1 0 0 0deg] +PASS Web Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (0.25) is [0 1 0 2.5deg] +PASS Web Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (0.75) is [0 1 0 7.5deg] +PASS Web Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (1) is [0 1 0 10deg] +PASS Web Animations: property <rotate> from [1 0 0 0deg] to [0 1 0 10deg] at (2) is [0 1 0 20deg] +PASS Web Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (-1) is [0.673392 -0.0631886 -0.73658 124.975deg] +PASS Web Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (0) is [1 1 0 90deg] +PASS Web Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (0.25) is [0.544172 0.799255 0.255083 94.834deg] +PASS Web Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (0.75) is [0.167111 0.775694 0.608583 118.679deg] +PASS Web Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (1) is [0 1 1 135deg] +PASS Web Animations: property <rotate> from [1 1 0 90deg] to [0 1 1 135deg] at (2) is [0.516398 -0.289524 -0.805921 151.045deg] +PASS Web Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (-1) is [1 0 0 -450deg] +PASS Web Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (0) is [0 1 0 0deg] +PASS Web Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (0.25) is [1 0 0 112.5deg] +PASS Web Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (0.75) is [1 0 0 337.5deg] +PASS Web Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (1) is [1 0 0 450deg] +PASS Web Animations: property <rotate> from [0 1 0 0deg] to [1 0 0 450deg] at (2) is [1 0 0 900deg] +PASS Web Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (-1) is [1 0 0 900deg] +PASS Web Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (0) is [1 0 0 450deg] +PASS Web Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (0.25) is [1 0 0 337.5deg] +PASS Web Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (0.75) is [1 0 0 112.5deg] +PASS Web Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (1) is [0 1 0 0deg] +PASS Web Animations: property <rotate> from [1 0 0 450deg] to [0 1 0 0deg] at (2) is [1 0 0 -450deg] +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/rotate-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/rotate-interpolation.html index 5eadc61..9df7e47 100644 --- a/third_party/WebKit/LayoutTests/animations/interpolation/rotate-interpolation.html +++ b/third_party/WebKit/LayoutTests/animations/interpolation/rotate-interpolation.html
@@ -23,6 +23,19 @@ <script> assertInterpolation({ property: 'rotate', + from: 'none', + to: '30deg', +}, [ + {at: -1, is: '-30deg'}, + {at: 0, is: 'none'}, + {at: 0.25, is: '7.5deg'}, + {at: 0.75, is: '22.5deg'}, + {at: 1, is: '30deg'}, + {at: 2, is: '60deg'}, +]); + +assertInterpolation({ + property: 'rotate', from: neutralKeyframe, to: '30deg', }, [ @@ -40,7 +53,7 @@ to: '30deg', }, [ {at: -1, is: '-30deg'}, - {at: 0, is: '0deg'}, + {at: 0, is: 'none'}, {at: 0.25, is: '7.5deg'}, {at: 0.75, is: '22.5deg'}, {at: 1, is: '30deg'}, @@ -115,14 +128,14 @@ assertInterpolation({ property: 'rotate', from: '1 1 0 90deg', - to: '0 1 1 180deg', + to: '0 1 1 135deg', }, [ - {at: -1, is: '0.41 -0.41 -0.82 120deg'}, + {at: -1, is: '0.67 -0.06 -0.74 124.97deg'}, {at: 0, is: '1 1 0 90deg'}, - {at: 0.25, is: '0.8 0.27 -0.53 82.76deg'}, - {at: 0.75, is: '0.27 -0.54 -0.8 138.89deg'}, - {at: 1, is: '0 1 1 180deg'}, - {at: 2, is: '0.71 0 -0.71 90deg'}, + {at: 0.25, is: '0.54 0.8 0.26 94.83deg'}, + {at: 0.75, is: '0.17 0.78 0.61 118.68deg'}, + {at: 1, is: '0 1 1 135deg'}, + {at: 2, is: '0.52 -0.29 -0.81 151.04deg'}, ]); assertInterpolation({
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/resources/responsive-test.js b/third_party/WebKit/LayoutTests/animations/responsive/resources/responsive-test.js index 5a35f5c..2c47f631 100644 --- a/third_party/WebKit/LayoutTests/animations/responsive/resources/responsive-test.js +++ b/third_party/WebKit/LayoutTests/animations/responsive/resources/responsive-test.js
@@ -70,6 +70,9 @@ return createElement('div', container, 'target'); }, setValue(target, property, value) { + test(function() { + assert_true(CSS.supports(property, value), 'CSS.supports ' + property + ' ' + value); + }); target.style[property] = value; }, getAnimatedValue(target, property) {
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/rotate-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/rotate-responsive.html index 7710fbd1..ee12a37 100644 --- a/third_party/WebKit/LayoutTests/animations/responsive/rotate-responsive.html +++ b/third_party/WebKit/LayoutTests/animations/responsive/rotate-responsive.html
@@ -4,18 +4,18 @@ assertCSSResponsive({ property: 'rotate', from: 'inherit', - to: '100deg 0 1 0', + to: '0 1 0 100deg', configurations: [{ - state: {inherited: '60deg 0 1 0'}, + state: {inherited: '0 1 0 60deg'}, expect: [ - {at: 0.25, is: '70deg 0 1 0'}, - {at: 0.75, is: '90deg 0 1 0'}, + {at: 0.25, is: '0 1 0 70deg'}, + {at: 0.75, is: '0 1 0 90deg'}, ], }, { - state: {inherited: '140deg 0 1 0'}, + state: {inherited: '0 1 0 140deg'}, expect: [ - {at: 0.25, is: '130deg 0 1 0'}, - {at: 0.75, is: '110deg 0 1 0'}, + {at: 0.25, is: '0 1 0 130deg'}, + {at: 0.75, is: '0 1 0 110deg'}, ], }], });
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/transform-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/transform-responsive.html index 57d3f14e6..67c75e1 100644 --- a/third_party/WebKit/LayoutTests/animations/responsive/transform-responsive.html +++ b/third_party/WebKit/LayoutTests/animations/responsive/transform-responsive.html
@@ -6,13 +6,13 @@ from: 'translateX(10em)', to: 'translateX(100px)', configurations: [{ - state: {fontSize: '2px'}, + state: {'font-size': '2px'}, expect: [ {at: 0.25, is: 'translateX(40px)'}, {at: 0.75, is: 'translateX(80px)'}, ], }, { - state: {fontSize: '6px'}, + state: {'font-size' '6px'}, expect: [ {at: 0.25, is: 'translateX(70px)'}, {at: 0.75, is: 'translateX(90px)'},
diff --git a/third_party/WebKit/LayoutTests/compositing/fixed-body-background-positioned-expected.txt b/third_party/WebKit/LayoutTests/compositing/fixed-body-background-positioned-expected.txt index 4c9b383..7626c39 100644 --- a/third_party/WebKit/LayoutTests/compositing/fixed-body-background-positioned-expected.txt +++ b/third_party/WebKit/LayoutTests/compositing/fixed-body-background-positioned-expected.txt
@@ -1,6 +1,24 @@ { "layers": [ { + "name": "Inner Viewport Container Layer", + "bounds": [800, 600] + }, + { + "name": "Overscroll Elasticity Layer" + }, + { + "name": "Page Scale Layer" + }, + { + "name": "Inner Viewport Scroll Layer", + "bounds": [800, 600] + }, + { + "name": "Frame Overflow Controls Host Layer", + "bounds": [800, 600] + }, + { "name": "Frame Clipping Layer", "bounds": [785, 600] }, @@ -22,6 +40,12 @@ "name": "LayoutView #document", "bounds": [785, 3700], "drawsContent": true + }, + { + "name": "Frame Vertical Scrollbar Layer", + "position": [785, 0], + "bounds": [15, 600], + "contentsOpaque": true } ] }
diff --git a/third_party/WebKit/LayoutTests/compositing/video/video-reflection-expected.png b/third_party/WebKit/LayoutTests/compositing/video/video-reflection-expected.png deleted file mode 100644 index 3f8a497..0000000 --- a/third_party/WebKit/LayoutTests/compositing/video/video-reflection-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/css3/flexbox/change-flexitem-into-abspos.html b/third_party/WebKit/LayoutTests/css3/flexbox/change-flexitem-into-abspos.html new file mode 100644 index 0000000..34bd742 --- /dev/null +++ b/third_party/WebKit/LayoutTests/css3/flexbox/change-flexitem-into-abspos.html
@@ -0,0 +1,39 @@ +<!DOCTYPE html> + +<style> +#flex { + display: flex; + position: relative; + background: red; + width: 500px; + height: 200px; +} + +#item { + background: green; + left: 0; + right: 0; + top: 0; + bottom: 0; +} +</style> + +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="../../resources/check-layout-th.js"></script> + +<script> +function update() { + var item = document.getElementById("item"); + item.offsetHeight; + item.style.position = "absolute"; + item.offsetHeight; + checkLayout("#flex"); +} +</script> + +<body onload="update();"> + +<div id="flex"> + <div id="item" data-expected-width="500"></div> +</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/FileAPI/reading-data-section/FileReader-multiple-reads.html b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/reading-data-section/FileReader-multiple-reads.html index b74b3f2..ca04f3c 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/FileAPI/reading-data-section/FileReader-multiple-reads.html +++ b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/reading-data-section/FileReader-multiple-reads.html
@@ -69,5 +69,5 @@ }); reader.readAsArrayBuffer(blob_1) assert_equals(reader.readyState, FileReader.LOADING, "readyState Must be LOADING") -}, 'test FileReader no InvalidStateError exception in onloadstart event for readAsArrayBuffer'); +}, 'test FileReader no InvalidStateError exception in loadend event handler for readAsArrayBuffer'); </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/FileAPI/reading-data-section/filereader_abort.html b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/reading-data-section/filereader_abort.html index a96389c2..940a775 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/FileAPI/reading-data-section/filereader_abort.html +++ b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/reading-data-section/filereader_abort.html
@@ -19,28 +19,35 @@ assert_equals(readerNoRead.result, null); }, "Aborting before read"); - async_test(function() { - var blob = new Blob(["TEST THE ABORT METHOD"]); - var readerAbort = new FileReader(); + promise_test(t => { + var blob = new Blob(["TEST THE ABORT METHOD"]); + var readerAbort = new FileReader(); - readerAbort.onabort = this.step_func(function(evt) { - assert_equals(readerAbort.readyState, readerAbort.DONE); - }); + var eventWatcher = new EventWatcher(t, readerAbort, + ['abort', 'loadstart', 'loadend', 'error', 'load']); - readerAbort.onloadstart = this.step_func(function(evt) { - assert_equals(readerAbort.readyState, readerAbort.LOADING); - readerAbort.abort(); - }); + // EventWatcher doesn't let us inspect the state after the abort event, + // so add an extra event handler for that. + readerAbort.addEventListener('abort', t.step_func(e => { + assert_equals(readerAbort.readyState, readerAbort.DONE); + })); - readerAbort.onloadend = this.step_func(function(evt) { - // https://www.w3.org/Bugs/Public/show_bug.cgi?id=24401 - assert_equals(readerAbort.result, null); - assert_equals(readerAbort.readyState, readerAbort.DONE); - this.done(); - }); - - readerAbort.readAsText(blob); - }, "Aborting after read"); + readerAbort.readAsText(blob); + return eventWatcher.wait_for('loadstart') + .then(() => { + assert_equals(readerAbort.readyState, readerAbort.LOADING); + // 'abort' and 'loadend' events are dispatched synchronously, so + // call wait_for before calling abort. + var nextEvent = eventWatcher.wait_for(['abort', 'loadend']); + readerAbort.abort(); + return nextEvent; + }) + .then(() => { + // https://www.w3.org/Bugs/Public/show_bug.cgi?id=24401 + assert_equals(readerAbort.result, null); + assert_equals(readerAbort.readyState, readerAbort.DONE); + }); + }, "Aborting after read"); </script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/FileAPI/url/blob-url-in-sandboxed-iframe.html b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/url/blob-url-in-sandboxed-iframe.html new file mode 100644 index 0000000..7d032496 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/url/blob-url-in-sandboxed-iframe.html
@@ -0,0 +1,66 @@ +<!doctype html> +<meta charset="utf-8"> +<title>FileAPI Test: Creating Blob URL with Blob</title> +<link rel="author" title="Victor Costan" href="mailto:pwnall@chromium.org"> +<link rel="help" href="https://w3c.github.io/FileAPI/#originOfBlobURL"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/browsers.html#concept-origin"> +<link rel="help" href="https://url.spec.whatwg.org/#url-parsing"> +<link rel="help" href="https://fetch.spec.whatwg.org/#main-fetch"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<style> +iframe { width: 10px; height: 10px; } +</style> + +<iframe id="unconstrained-iframe"></iframe> +<iframe id="sandboxed-iframe" sandbox="allow-scripts"></iframe> + +<script id="iframe-srcdoc" language="text/html"> +<!doctype html> +<script> +'use strict'; + +window.onload = () => { + const blob = new Blob(['Hello world!']); + const blobUrl = URL.createObjectURL(blob); + + fetch(blobUrl).then(response => response.text()).then(text => { + window.parent.postMessage({ blobUrl, text }, '*'); + }); +}; +// The script tag is closed in readBlobFromUrl(). +</script> + +<script> + +// Carries out the test of minting a Blob URL in an iframe, and reading it back. +// +// Returns a promise resolved with an object with properties blobUrl and text +// (the text read back from the Blob URL). +function readBlobFromUrl(t, iframeSelector) { + return new Promise((resolve, reject) => { + window.onmessage = t.step_func((message) => { resolve(message.data); }); + + const frame = document.querySelector(iframeSelector); + const html = document.querySelector('#iframe-srcdoc').textContent + + '<' + '/script>'; + frame.setAttribute('srcdoc', html); + }); +} + +promise_test(t => readBlobFromUrl(t, '#unconstrained-iframe').then(data => { + assert_true(data.blobUrl.startsWith('blob:'), + "The Blob's URL should use the blob: scheme"); + assert_equals(data.text, 'Hello world!', + "The result of reading the Blob's URL should be the Blob's contents"); +}), 'reading a Blob URL in an unconstrained iframe'); + +promise_test(t => readBlobFromUrl(t, '#sandboxed-iframe').then(data => { + assert_true(data.blobUrl.startsWith('blob:'), + "The Blob's URL should use the blob: scheme"); + assert_equals(data.text, 'Hello world!', + "The result of reading the Blob's URL should be the Blob's contents"); +}), 'reading a Blob URL in a sandboxed iframe without the same-origin flag'); + +</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/clone-before-keypath-eval.html b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/clone-before-keypath-eval.html new file mode 100644 index 0000000..bf67c5d --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/clone-before-keypath-eval.html
@@ -0,0 +1,135 @@ +<!doctype html> +<meta charset=utf-8> +<title>IndexedDB: </title> +<meta name="help" href="https://w3c.github.io/IndexedDB/#dom-idbobjectstore-put"> +<meta name="help" href="https://w3c.github.io/IndexedDB/#dom-idbcursor-update"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support.js"></script> +<script> + +function ProbeObject() { + this.id_count = 0; + this.invalid_id_count = 0; + this.prop_count = 0; + Object.defineProperties(this, { + id: { + enumerable: true, + get() { + ++this.id_count; + return 1000 + this.id_count; + }, + }, + invalid_id: { + enumerable: true, + get() { + ++this.invalid_id_count; + return {}; + }, + }, + prop: { + enumerable: true, + get() { + ++this.prop_count; + return 2000 + this.prop_count; + }, + }, + }); +} + +indexeddb_test( + (t, db) => { + db.createObjectStore('store', {keyPath: 'id', autoIncrement: true}); + }, + (t, db) => { + const tx = db.transaction('store', 'readwrite'); + const store = tx.objectStore('store'); + const obj = new ProbeObject(); + store.put(obj); + assert_equals( + obj.id_count, 1, + 'put() operation should access primary key property once'); + assert_equals( + obj.prop_count, 1, + 'put() operation should access other properties once'); + t.done(); + }, 'Key generator and key path validity check operates on a clone'); + +indexeddb_test( + (t, db) => { + db.createObjectStore('store', {keyPath: 'invalid_id', autoIncrement: true}); + }, + (t, db) => { + const tx = db.transaction('store', 'readwrite'); + const store = tx.objectStore('store'); + const obj = new ProbeObject(); + assert_throws('DataError', () => { store.put(obj); }, + 'put() should throw if primary key cannot be injected'); + assert_equals( + obj.invalid_id_count, 1, + 'put() operation should access primary key property once'); + assert_equals( + obj.prop_count, 1, + 'put() operation should access other properties once'); + t.done(); + }, 'Failing key path validity check operates on a clone'); + +indexeddb_test( + (t, db) => { + const store = db.createObjectStore('store'); + store.createIndex('index', 'prop'); + }, + (t, db) => { + const tx = db.transaction('store', 'readwrite'); + const store = tx.objectStore('store'); + const obj = new ProbeObject(); + store.put(obj, 'key'); + assert_equals( + obj.prop_count, 1, 'put() should access index key property once'); + assert_equals( + obj.id_count, 1, + 'put() operation should access other properties once'); + t.done(); + }, 'Index key path evaluations operate on a clone'); + +indexeddb_test( + (t, db) => { + const store = db.createObjectStore('store', {keyPath: 'id'}); + store.createIndex('index', 'prop'); + }, + (t, db) => { + const tx = db.transaction('store', 'readwrite'); + const store = tx.objectStore('store'); + const obj = new ProbeObject(); + store.put(obj); + assert_equals( + obj.id_count, 1, 'put() should access primary key property once'); + assert_equals( + obj.prop_count, 1, 'put() should access index key property once'); + t.done(); + }, 'Store and index key path evaluations operate on the same clone'); + +indexeddb_test( + (t, db) => { + const store = db.createObjectStore('store', {keyPath: 'id'}); + store.createIndex('index', 'prop'); + }, + (t, db) => { + const tx = db.transaction('store', 'readwrite'); + const store = tx.objectStore('store'); + store.put(new ProbeObject()); + + store.openCursor().onsuccess = t.step_func((event) => { + const cursor = event.target.result; + + const obj = new ProbeObject(); + cursor.update(obj); + assert_equals( + obj.id_count, 1, 'put() should access primary key property once'); + assert_equals( + obj.prop_count, 1, 'put() should access index key property once'); + + t.done(); + }); + }, 'Cursor update checks and keypath evaluations operate on a clone'); +</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/idbversionchangeevent.htm b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/idbversionchangeevent.htm index 866a8b2eb..36b997f 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/idbversionchangeevent.htm +++ b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/idbversionchangeevent.htm
@@ -51,10 +51,28 @@ var deleterq = indexedDB.deleteDatabase('db'); deleterq.onsuccess = t.step_func(function(e) { + assert_equals(e.result, undefined, "result (delete.success for nonexistent db)"); assert_equals(e.oldVersion, 3, "old version (delete.success)"); assert_equals(e.newVersion, null, "new version (delete.success)"); assert_true(e instanceof IDBVersionChangeEvent, "delete.success instanceof IDBVersionChangeEvent"); + setTimeout(deleteNonExistentDB, 10); + }); + + // Errors + deleterq.onerror = fail(t, "delete.error"); + deleterq.onblocked = fail(t, "delete.blocked"); + } + + function deleteNonExistentDB (e) { + var deleterq = indexedDB.deleteDatabase('db-does-not-exist'); + + deleterq.onsuccess = t.step_func(function(e) { + assert_equals(e.result, undefined, "result (delete.success for nonexistent db)"); + assert_equals(e.oldVersion, 0, "old version (delete.success for nonexistent db)"); + assert_equals(e.newVersion, null, "new version (delete.success for nonexistent db)"); + assert_true(e instanceof IDBVersionChangeEvent, "delete.success instanceof IDBVersionChangeEvent"); + setTimeout(function() { t.done(); }, 10); });
diff --git a/third_party/WebKit/LayoutTests/storage/indexeddb/key_conversion_exceptions.html b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/key-conversion-exceptions.htm similarity index 67% rename from third_party/WebKit/LayoutTests/storage/indexeddb/key_conversion_exceptions.html rename to third_party/WebKit/LayoutTests/external/wpt/IndexedDB/key-conversion-exceptions.htm index 23ed89be..608d0f9a 100644 --- a/third_party/WebKit/LayoutTests/storage/indexeddb/key_conversion_exceptions.html +++ b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/key-conversion-exceptions.htm
@@ -1,24 +1,14 @@ -<!DOCTYPE html> +<!doctype html> +<meta charset=utf-8> <title>IndexedDB: Exceptions thrown during key conversion</title> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support.js"></script> <script> -function simple_idb_test(upgrade_callback, description) { - async_test(function(t) { - var dbname = document.location + '-' + t.name; - var del = indexedDB.deleteDatabase(dbname); - del.onerror = t.unreached_func('deleteDatabase should succeed'); - var open = indexedDB.open(dbname); - open.onerror = t.unreached_func('open should succeed'); - open.onupgradeneeded = t.step_func(function(e) { - upgrade_callback(t, open.result); - }); - open.onsuccess = t.step_func(function() { - open.result.close(); - t.done(); - }); - }, description); +// Convenience function for tests that only need to run code in onupgradeneeded. +function indexeddb_upgrade_only_test(upgrade_callback, description) { + indexeddb_test(upgrade_callback, t => { t.done(); }, description); } // Key that throws during conversion. @@ -44,80 +34,80 @@ function check_method(receiver, method, args) { args = args || 1; if (args < 2) { - assert_throws({name:'getter'}, function() { + assert_throws({name:'getter'}, () => { receiver[method](throwing_key('getter')); }, 'key conversion with throwing getter should rethrow'); - assert_throws('DataError', function() { + assert_throws('DataError', () => { receiver[method](invalid_key); }, 'key conversion with invalid key should throw DataError'); } else { - assert_throws({name:'getter 1'}, function() { + assert_throws({name:'getter 1'}, () => { receiver[method](throwing_key('getter 1'), throwing_key('getter 2')); }, 'first key conversion with throwing getter should rethrow'); - assert_throws('DataError', function() { + assert_throws('DataError', () => { receiver[method](invalid_key, throwing_key('getter 2')); }, 'first key conversion with invalid key should throw DataError'); - assert_throws({name:'getter 2'}, function() { + assert_throws({name:'getter 2'}, () => { receiver[method](valid_key, throwing_key('getter 2')); }, 'second key conversion with throwing getter should rethrow'); - assert_throws('DataError', function() { + assert_throws('DataError', () => { receiver[method](valid_key, invalid_key); }, 'second key conversion with invalid key should throw DataError'); } } // Static key comparison utility on IDBFactory. -test(function(t) { +test(t => { check_method(indexedDB, 'cmp', 2); }, 'IDBFactory cmp() static with throwing/invalid keys'); // Continue methods on IDBCursor. -simple_idb_test(function(t, db) { +indexeddb_upgrade_only_test((t, db) => { var store = db.createObjectStore('store'); store.put('a', 1).onerror = t.unreached_func('put should succeed'); var request = store.openCursor(); request.onerror = t.unreached_func('openCursor should succeed'); - request.onsuccess = t.step_func(function() { + request.onsuccess = t.step_func(() => { var cursor = request.result; assert_not_equals(cursor, null, 'cursor should find a value'); check_method(cursor, 'continue'); }); }, 'IDBCursor continue() method with throwing/invalid keys'); -simple_idb_test(function(t, db) { +indexeddb_upgrade_only_test((t, db) => { var store = db.createObjectStore('store'); var index = store.createIndex('index', 'prop'); store.put({prop: 'a'}, 1).onerror = t.unreached_func('put should succeed'); var request = index.openCursor(); request.onerror = t.unreached_func('openCursor should succeed'); - request.onsuccess = t.step_func(function() { + request.onsuccess = t.step_func(() => { var cursor = request.result; assert_not_equals(cursor, null, 'cursor should find a value'); check_method(cursor, 'continuePrimaryKey', 2); }); -}, 'IDBCursor continuePrimaryKey() method with throwing/invalid keys'); +}, null, 'IDBCursor continuePrimaryKey() method with throwing/invalid keys'); // Mutation methods on IDBCursor. -simple_idb_test(function(t, db) { +indexeddb_upgrade_only_test((t, db) => { var store = db.createObjectStore('store', {keyPath: 'prop'}); store.put({prop: 1}).onerror = t.unreached_func('put should succeed'); var request = store.openCursor(); request.onerror = t.unreached_func('openCursor should succeed'); - request.onsuccess = t.step_func(function() { + request.onsuccess = t.step_func(() => { var cursor = request.result; assert_not_equals(cursor, null, 'cursor should find a value'); var value = {}; value.prop = throwing_key('getter'); - assert_throws({name: 'getter'}, function() { + assert_throws({name: 'getter'}, () => { cursor.update(value); }, 'throwing getter should rethrow during clone'); @@ -127,40 +117,40 @@ // are used for key path evaluation. value.prop = invalid_key; - assert_throws('DataError', function() { + assert_throws('DataError', () => { cursor.update(value); }, 'key conversion with invalid key should throw DataError'); }); }, 'IDBCursor update() method with throwing/invalid keys'); // Static constructors on IDBKeyRange -['only', 'lowerBound', 'upperBound'].forEach(function(method) { - test(function(t) { +['only', 'lowerBound', 'upperBound'].forEach(method => { + test(t => { check_method(IDBKeyRange, method); }, 'IDBKeyRange ' + method + '() static with throwing/invalid keys'); }); -test(function(t) { +test(t => { check_method(IDBKeyRange, 'bound', 2); }, 'IDBKeyRange bound() static with throwing/invalid keys'); // Insertion methods on IDBObjectStore. -['add', 'put'].forEach(function(method) { - simple_idb_test(function(t, db) { +['add', 'put'].forEach(method => { + indexeddb_upgrade_only_test((t, db) => { var out_of_line = db.createObjectStore('out-of-line keys'); var in_line = db.createObjectStore('in-line keys', {keyPath: 'prop'}); - assert_throws({name:'getter'}, function() { + assert_throws({name:'getter'}, () => { out_of_line[method]('value', throwing_key('getter')); }, 'key conversion with throwing getter should rethrow'); - assert_throws('DataError', function() { + assert_throws('DataError', () => { out_of_line[method]('value', invalid_key); }, 'key conversion with invalid key should throw DataError'); var value = {}; value.prop = throwing_key('getter'); - assert_throws({name:'getter'}, function() { + assert_throws({name:'getter'}, () => { in_line[method](value); }, 'throwing getter should rethrow during clone'); @@ -170,35 +160,35 @@ // are used for key path evaluation. value.prop = invalid_key; - assert_throws('DataError', function() { + assert_throws('DataError', () => { in_line[method](value); }, 'key conversion with invalid key should throw DataError'); - }, 'IDBObjectStore ' + method + '() method with throwing/invalid keys'); + }, `IDBObjectStore ${method}() method with throwing/invalid keys`); }); // Generic (key-or-key-path) methods on IDBObjectStore. [ - // TODO(jsbell): Add 'getAllKeys' - 'delete', 'get', 'getAll', 'count', 'openCursor', 'openKeyCursor' -].forEach(function(method) { - simple_idb_test(function(t, db) { + 'delete', 'get', 'getKey', 'getAll', 'getAllKeys', 'count', 'openCursor', + 'openKeyCursor' +].forEach(method => { + indexeddb_upgrade_only_test((t, db) => { var store = db.createObjectStore('store'); check_method(store, method); - }, 'IDBObjectStore ' + method + '() method with throwing/invalid keys'); + }, `IDBObjectStore ${method}() method with throwing/invalid keys`); }); // Generic (key-or-key-path) methods on IDBIndex. [ - // TODO(jsbell): Add 'getAllKeys' - 'get', 'getKey', 'getAll', 'count', 'openCursor', 'openKeyCursor' -].forEach(function(method) { - simple_idb_test(function(t, db) { + 'get', 'getKey', 'getAll', 'getAllKeys', 'count', 'openCursor', + 'openKeyCursor' +].forEach(method => { + indexeddb_upgrade_only_test((t, db) => { var store = db.createObjectStore('store'); var index = store.createIndex('index', 'keyPath'); check_method(index, method); - }, 'IDBIndex ' + method + '() method with throwing/invalid keys'); + }, `IDBIndex ${method}() method with throwing/invalid keys`); }); </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/MANIFEST.json b/third_party/WebKit/LayoutTests/external/wpt/MANIFEST.json index 7897bf3..0cfcbca 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/MANIFEST.json +++ b/third_party/WebKit/LayoutTests/external/wpt/MANIFEST.json
@@ -4197,11 +4197,6 @@ {} ] ], - "dom/events/Event-init-while-dispatching-expected.txt": [ - [ - {} - ] - ], "dom/events/Event-subclasses-constructors-expected.txt": [ [ {} @@ -4622,6 +4617,11 @@ {} ] ], + "dom/nodes/MutationObserver-childList-expected.txt": [ + [ + {} + ] + ], "dom/nodes/MutationObserver-document-expected.txt": [ [ {} @@ -4757,11 +4757,6 @@ {} ] ], - "dom/ranges/Range-mutations-appendChild-expected.txt": [ - [ - {} - ] - ], "dom/ranges/Range-mutations-dataChange-expected.txt": [ [ {} @@ -4772,16 +4767,6 @@ {} ] ], - "dom/ranges/Range-mutations-insertBefore-expected.txt": [ - [ - {} - ] - ], - "dom/ranges/Range-mutations-replaceChild-expected.txt": [ - [ - {} - ] - ], "dom/ranges/Range-mutations-splitText-expected.txt": [ [ {} @@ -6477,11 +6462,6 @@ {} ] ], - "html/browsers/origin/cross-origin-objects/cross-origin-objects-exceptions-expected.txt": [ - [ - {} - ] - ], "html/browsers/origin/cross-origin-objects/cross-origin-objects-expected.txt": [ [ {} @@ -6907,6 +6887,11 @@ {} ] ], + "html/dom/dynamic-markup-insertion/document-write/empty.html": [ + [ + {} + ] + ], "html/dom/dynamic-markup-insertion/document-write/iframe_005.js": [ [ {} @@ -6932,6 +6917,11 @@ {} ] ], + "html/dom/dynamic-markup-insertion/document-write/write-active-document-expected.txt": [ + [ + {} + ] + ], "html/dom/dynamic-markup-insertion/document-writeln/original-id.json": [ [ {} @@ -12707,6 +12697,11 @@ {} ] ], + "html/semantics/links/linktypes/alternate-import.css": [ + [ + {} + ] + ], "html/semantics/links/linktypes/alternate.css": [ [ {} @@ -13452,6 +13447,11 @@ {} ] ], + "html/webappapis/scripting/events/body-exposed-window-event-handlers-expected.txt": [ + [ + {} + ] + ], "html/webappapis/scripting/events/contains.json": [ [ {} @@ -14057,11 +14057,6 @@ {} ] ], - "pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual-expected.txt": [ - [ - {} - ] - ], "pointerevents/pointerevent_styles.css": [ [ {} @@ -14187,6 +14182,11 @@ {} ] ], + "remote-playback/README.md": [ + [ + {} + ] + ], "selection/Document-open-expected.txt": [ [ {} @@ -14967,6 +14967,11 @@ {} ] ], + "service-workers/service-worker/resources/link-header.py": [ + [ + {} + ] + ], "service-workers/service-worker/resources/load_worker.js": [ [ {} @@ -17224,6 +17229,12 @@ {} ] ], + "FileAPI/url/blob-url-in-sandboxed-iframe.html": [ + [ + "/FileAPI/url/blob-url-in-sandboxed-iframe.html", + {} + ] + ], "FileAPI/url/origin.sub.html": [ [ "/FileAPI/url/origin.sub.html", @@ -17254,6 +17265,12 @@ {} ] ], + "IndexedDB/clone-before-keypath-eval.html": [ + [ + "/IndexedDB/clone-before-keypath-eval.html", + {} + ] + ], "IndexedDB/close-in-upgradeneeded.html": [ [ "/IndexedDB/close-in-upgradeneeded.html", @@ -18918,6 +18935,12 @@ {} ] ], + "IndexedDB/key-conversion-exceptions.htm": [ + [ + "/IndexedDB/key-conversion-exceptions.htm", + {} + ] + ], "IndexedDB/key_invalid.htm": [ [ "/IndexedDB/key_invalid.htm", @@ -23126,14 +23149,6 @@ {} ] ], - "html/browsers/origin/cross-origin-objects/cross-origin-objects-exceptions.html": [ - [ - "/html/browsers/origin/cross-origin-objects/cross-origin-objects-exceptions.html", - { - "timeout": "long" - } - ] - ], "html/browsers/origin/cross-origin-objects/cross-origin-objects-on-new-window.html": [ [ "/html/browsers/origin/cross-origin-objects/cross-origin-objects-on-new-window.html", @@ -24166,6 +24181,12 @@ {} ] ], + "html/dom/dynamic-markup-insertion/document-write/write-active-document.html": [ + [ + "/html/dom/dynamic-markup-insertion/document-write/write-active-document.html", + {} + ] + ], "html/dom/dynamic-markup-insertion/document-writeln/document.writeln-01.xhtml": [ [ "/html/dom/dynamic-markup-insertion/document-writeln/document.writeln-01.xhtml", @@ -25594,6 +25615,12 @@ {} ] ], + "html/semantics/embedded-content/the-iframe-element/iframe-synchronously-discard.html": [ + [ + "/html/semantics/embedded-content/the-iframe-element/iframe-synchronously-discard.html", + {} + ] + ], "html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_01.htm": [ [ "/html/semantics/embedded-content/the-iframe-element/iframe_javascript_url_01.htm", @@ -25672,6 +25699,12 @@ {} ] ], + "html/semantics/embedded-content/the-img-element/not-rendered-dimension-getter.html": [ + [ + "/html/semantics/embedded-content/the-img-element/not-rendered-dimension-getter.html", + {} + ] + ], "html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute.html": [ [ "/html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute.html", @@ -28650,6 +28683,12 @@ {} ] ], + "html/webappapis/scripting/events/body-exposed-window-event-handlers.html": [ + [ + "/html/webappapis/scripting/events/body-exposed-window-event-handlers.html", + {} + ] + ], "html/webappapis/scripting/events/body-onload.html": [ [ "/html/webappapis/scripting/events/body-onload.html", @@ -29624,6 +29663,36 @@ {} ] ], + "remote-playback/cancel-watch-availability.html": [ + [ + "/remote-playback/cancel-watch-availability.html", + {} + ] + ], + "remote-playback/disable-remote-playback-cancel-watch-availability-throws.html": [ + [ + "/remote-playback/disable-remote-playback-cancel-watch-availability-throws.html", + {} + ] + ], + "remote-playback/disable-remote-playback-prompt-throws.html": [ + [ + "/remote-playback/disable-remote-playback-prompt-throws.html", + {} + ] + ], + "remote-playback/disable-remote-playback-watch-availability-throws.html": [ + [ + "/remote-playback/disable-remote-playback-watch-availability-throws.html", + {} + ] + ], + "remote-playback/watch-availability-initial-callback.html": [ + [ + "/remote-playback/watch-availability-initial-callback.html", + {} + ] + ], "selection/Document-open.html": [ [ "/selection/Document-open.html", @@ -30474,6 +30543,12 @@ {} ] ], + "service-workers/service-worker/register-link-header.https.html": [ + [ + "/service-workers/service-worker/register-link-header.https.html", + {} + ] + ], "service-workers/service-worker/register-same-scope-different-script-url.https.html": [ [ "/service-workers/service-worker/register-same-scope-different-script-url.https.html", @@ -34452,7 +34527,7 @@ "support" ], "./MANIFEST.json": [ - "3364d99562a170daf89ad09865f224bc7813fb9e", + "94e506242954020d69b5240f63d2ef297d537608", "support" ], "./README.md": [ @@ -34460,7 +34535,7 @@ "support" ], "./check_stability.py": [ - "81b2d6b1f7aa7d8c237fb715e7b91c235276befd", + "1f1090e0caffce4acb4cd151a7841ec2b0c2ab12", "support" ], "./ci_built_diff.sh": [ @@ -34612,11 +34687,11 @@ "testharness" ], "FileAPI/reading-data-section/FileReader-multiple-reads.html": [ - "8ff4ca7492de72b1764365a302fd74356b8ced21", + "32bad4f4ea2ac1104fa2828ef7370a2fdee11a5a", "testharness" ], "FileAPI/reading-data-section/filereader_abort.html": [ - "24891122dd1a2aea40bfa59a2e19431c449122a9", + "b1a3335d10f661aee31df179e5e81d2071b38edd", "testharness" ], "FileAPI/reading-data-section/filereader_error.html": [ @@ -34659,6 +34734,10 @@ "18972f4ed024eb5e1494ac466426ae32b3f5525f", "support" ], + "FileAPI/url/blob-url-in-sandboxed-iframe.html": [ + "59188b2e679f56d5eb7ea01428ce06ff0068111a", + "testharness" + ], "FileAPI/url/origin.sub.html": [ "427ede39094dacc910250495bc39ae5ad5826279", "testharness" @@ -34687,6 +34766,10 @@ "95f44900d9565baf718be23bafd33e48e6f4fc52", "testharness" ], + "IndexedDB/clone-before-keypath-eval.html": [ + "9191c591c5c820c0e6c91c21ba339b98ffc42b5a", + "testharness" + ], "IndexedDB/close-in-upgradeneeded.html": [ "949f5e8a429a7524c9a68ef0d19baf04dadbd84a", "testharness" @@ -35772,7 +35855,7 @@ "testharness" ], "IndexedDB/idbversionchangeevent.htm": [ - "0db27a811017a52b05dd669f99b2accdeecb5c0d", + "1c84321376076ef84257aaa6d05306c005484f2d", "testharness" ], "IndexedDB/idbworker.js": [ @@ -35799,6 +35882,10 @@ "7edbb0cce85708e4b578ceae18a833fd623cd976", "testharness" ], + "IndexedDB/key-conversion-exceptions.htm": [ + "66c9ee49f2689e8917e5206f1bd2b9759b755d53", + "testharness" + ], "IndexedDB/key_invalid.htm": [ "8c0257c4231c413dde10c6f541f17f57634bff1c", "testharness" @@ -36487,10 +36574,6 @@ "d4385b80c2575fc81d1d93504b8a14b74c93bd85", "testharness" ], - "dom/events/Event-init-while-dispatching-expected.txt": [ - "b8c260b7e47e827d35a964196525e7dfa53fbc94", - "support" - ], "dom/events/Event-init-while-dispatching.html": [ "84e38be2f0e8f3c4f44a95cc296096de3631624b", "testharness" @@ -36556,7 +36639,7 @@ "testharness" ], "dom/events/EventTarget-dispatchEvent-expected.txt": [ - "f1c321223977fc3aed215fe3dc64cf842fa0558f", + "103c88a2a76fba190a3ccefd0867698ee0af9c4a", "support" ], "dom/events/EventTarget-dispatchEvent-returnvalue.html": [ @@ -36584,7 +36667,7 @@ "testharness" ], "dom/interfaces-expected.txt": [ - "736c279a0fd985f14413551d6ce01f5393416265", + "f403c23e7b24229e9fe438dbfd9f8a5e439a1fbd", "support" ], "dom/interfaces.html": [ @@ -37016,7 +37099,7 @@ "support" ], "dom/nodes/Document-createEvent-expected.txt": [ - "782f3ea80f40f8b1323b10fa6874da5ada7664e9", + "6fb89355db5fee22062b30c9bed9ae786add2ea1", "support" ], "dom/nodes/Document-createEvent.html": [ @@ -37299,6 +37382,10 @@ "ecf8cba9842dc6fed4b678a40c039389088c9d6e", "testharness" ], + "dom/nodes/MutationObserver-childList-expected.txt": [ + "f58c868768930e0c38a9911e89bfde53f4d11b73", + "support" + ], "dom/nodes/MutationObserver-childList.html": [ "91826df379f2edb53ab2d5d408905636512eeb28", "testharness" @@ -37452,7 +37539,7 @@ "testharness" ], "dom/nodes/Node-replaceChild-expected.txt": [ - "d6ce469f8a342c3d7053474916bb5ca402daf7fb", + "c3bd5e37d0be4bd282c2db5002117699b668bb79", "support" ], "dom/nodes/Node-replaceChild.html": [ @@ -37464,7 +37551,7 @@ "testharness" ], "dom/nodes/NodeList-Iterable.html": [ - "0f809f6016bd766de6cfc5a36588c0e3ef76ffa4", + "5f5ff52322f53a282b7b1cf37f452f58c274de92", "testharness" ], "dom/nodes/ParentNode-append.html": [ @@ -37787,10 +37874,6 @@ "99cd69da0d76b1ac128ee7c155d85f3be40dc088", "testharness" ], - "dom/ranges/Range-mutations-appendChild-expected.txt": [ - "67884ea2071e3729ea6702fd3df9fc5fb5cd26a6", - "support" - ], "dom/ranges/Range-mutations-appendChild.html": [ "5506bcbb1469bb727a5b0a5ce4339048959cdafb", "testharness" @@ -37800,7 +37883,7 @@ "testharness" ], "dom/ranges/Range-mutations-dataChange-expected.txt": [ - "edf4692d792c0bde9b7a4313e22e40936a503c0c", + "372d3f8bcd17916497417dcf9d1aa0ae5156cba7", "support" ], "dom/ranges/Range-mutations-dataChange.html": [ @@ -37815,10 +37898,6 @@ "45a88d19ceff57f8b6b5ad09e3c7bdcb2a1996a6", "support" ], - "dom/ranges/Range-mutations-insertBefore-expected.txt": [ - "06a490d95a09f963392c0745de7f34c5ad3cd71b", - "support" - ], "dom/ranges/Range-mutations-insertBefore.html": [ "efa7479a1249f6ef37c1ffffe6f01f9c9cacc69c", "testharness" @@ -37831,10 +37910,6 @@ "bca8ea0dfb51f83d0ec4a4adf70808c629db8027", "testharness" ], - "dom/ranges/Range-mutations-replaceChild-expected.txt": [ - "d6e6ebe1b735effc6919fc4dcd5bde56cf48cf04", - "support" - ], "dom/ranges/Range-mutations-replaceChild.html": [ "abede1c9cb2c08f7de4bfc4c57b8e21fe6a01fea", "testharness" @@ -39112,7 +39187,7 @@ "testharness" ], "hr-time/idlharness-expected.txt": [ - "ed498ef97d19552f6e4d376ea49c099136614d69", + "bb9c7549a8514d7906753a36550f1f51cdf85ca9", "support" ], "hr-time/idlharness.html": [ @@ -39568,11 +39643,11 @@ "support" ], "html/browsers/browsing-the-web/read-media/pageload-image.html": [ - "ab8233f67d7c4b694243d60b435100cad19cae17", + "b6710a9c29c09b52db31c9379e933649982dfe09", "testharness" ], "html/browsers/browsing-the-web/read-media/pageload-video.html": [ - "c3d7d9a9c75a0174a179b65c46a207910835387c", + "2d8749e1d5f585ba60ce0a20367d116d126df475", "testharness" ], "html/browsers/browsing-the-web/read-text/load-text-plain.html": [ @@ -40655,14 +40730,6 @@ "302b651285dd9e4367a90ce48070a3854ad3d0a2", "support" ], - "html/browsers/origin/cross-origin-objects/cross-origin-objects-exceptions-expected.txt": [ - "5074e545dc1000b55718c5c6bd9de0a7b6832a9c", - "support" - ], - "html/browsers/origin/cross-origin-objects/cross-origin-objects-exceptions.html": [ - "9f9f6d11d0444daf297a75ce1301e7300aef94f0", - "testharness" - ], "html/browsers/origin/cross-origin-objects/cross-origin-objects-expected.txt": [ "94b45bfb4fbf4ebd1b3c126df025440d176209ac", "support" @@ -40672,7 +40739,7 @@ "testharness" ], "html/browsers/origin/cross-origin-objects/cross-origin-objects.html": [ - "4397388c56189b03b7cf2fb195449fff6c895c81", + "4acb7047fa505deba20030e6ee83e9e4b55349a8", "testharness" ], "html/browsers/origin/cross-origin-objects/frame.html": [ @@ -41619,6 +41686,10 @@ "f4c6db3136e0860d38fe21193a0012eb5e4842ef", "testharness" ], + "html/dom/dynamic-markup-insertion/document-write/empty.html": [ + "b1149d9764ff4a9a7e8698f7a56ed003796d8582", + "support" + ], "html/dom/dynamic-markup-insertion/document-write/iframe_001.html": [ "1c9c5a787612667df557c57cb1ec5e101a38dfab", "testharness" @@ -41731,6 +41802,14 @@ "0c45797b8e51b33aa49148eff24e021b69c372d9", "testharness" ], + "html/dom/dynamic-markup-insertion/document-write/write-active-document-expected.txt": [ + "4a0a7a7c2c9826da0d42c938abf4ba95499c31b9", + "support" + ], + "html/dom/dynamic-markup-insertion/document-write/write-active-document.html": [ + "66d780431c740841834f0af67d20d28ac5178d9b", + "testharness" + ], "html/dom/dynamic-markup-insertion/document-writeln/document.writeln-01.xhtml": [ "443e8d9d653feb514dfc3cb8a1b4cb204ef38820", "testharness" @@ -47471,6 +47550,10 @@ "d45f7b847e30fe8e3c2e03ef838b55d11ef4592f", "testharness" ], + "html/semantics/embedded-content/the-iframe-element/iframe-synchronously-discard.html": [ + "8f2c79784636cd93a2a40c89c5d8298d4e0b7ec8", + "testharness" + ], "html/semantics/embedded-content/the-iframe-element/iframe-with-base-ref.html": [ "9e04580af238e0aea1f124e1748b0a008ddb8a0b", "support" @@ -47607,6 +47690,10 @@ "ed3a4e8ec0ffe8411176c91de37e965f252534cd", "testharness" ], + "html/semantics/embedded-content/the-img-element/not-rendered-dimension-getter.html": [ + "3752b0f4f5b31ca0bf55b99a400dd8cd7a12b8a7", + "testharness" + ], "html/semantics/embedded-content/the-img-element/resources/cat.jpg": [ "d8bdb2208a32d2200afb173368c38826fede8476", "support" @@ -48731,8 +48818,12 @@ "966681ecc3eb32b75867711fc938c3f903b5f572", "reftest" ], + "html/semantics/links/linktypes/alternate-import.css": [ + "07b1c2d78ec359fe1a036080d2019cbfe277f11c", + "support" + ], "html/semantics/links/linktypes/alternate.css": [ - "b4bc9956adc0edad4e9759161bead825ec2f36bb", + "61295dd4d20d8cabcd4c2bcb51f47107682ad033", "support" ], "html/semantics/links/linktypes/contains.json": [ @@ -50339,6 +50430,14 @@ "3907beccfe4fddca1b2326f737bde4e87979926e", "testharness" ], + "html/webappapis/scripting/events/body-exposed-window-event-handlers-expected.txt": [ + "d20f665d2ab2fdd631e2296c7b9a94738e8c3272", + "support" + ], + "html/webappapis/scripting/events/body-exposed-window-event-handlers.html": [ + "d5c9f5ddded8fa916f7e63a90d45fc9e01aa34a6", + "testharness" + ], "html/webappapis/scripting/events/body-onload.html": [ "c8e48064f18b1d1eb13e151b69ee60b8d68f4dab", "testharness" @@ -51184,7 +51283,7 @@ "testharness" ], "navigation-timing/nav2_test_attributes_values.html": [ - "75e8c32b7ed8c25742fe6a4358fd2abe1af813f6", + "f13d01f6c6cfa90b2bd92312b3c2e1c1b3aeed59", "testharness" ], "navigation-timing/nav2_test_document_open.html": [ @@ -51192,7 +51291,7 @@ "testharness" ], "navigation-timing/nav2_test_instance_accessors.html": [ - "49311fe1f5609f84eeb5fbcd6118f769a5c4a65e", + "c4960ce93c9379763845fb2cae9249d4e4c18376", "testharness" ], "navigation-timing/nav2_test_navigate_within_document.html": [ @@ -51412,7 +51511,7 @@ "manual" ], "pointerevents/pointerevent_lostpointercapture_for_disconnected_node-manual.html": [ - "04281aadb5dc8700ea999317090273113539ca49", + "be37ae30b37e73c9281757bc4a7bbe296f3ed76b", "manual" ], "pointerevents/pointerevent_lostpointercapture_is_first-manual.html": [ @@ -51475,12 +51574,8 @@ "84cf51a88c825b491594d6e91cd103fbea30cc60", "manual" ], - "pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual-expected.txt": [ - "db71b38ed1cc9a31aacc65da39425c43cc5c1f7e", - "support" - ], "pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html": [ - "b2de73875ec86676b22a6b6b77f5837dbc47271d", + "3f75075494c8ea9197bb9af0c08b5b85ef2c52ac", "manual" ], "pointerevents/pointerevent_releasepointercapture_invalid_pointerid-manual.html": [ @@ -51819,6 +51914,30 @@ "1e896cad5c89bfe1756af5db60b61bc9fa93f61b", "testharness" ], + "remote-playback/README.md": [ + "f76a7ece018ba65d920c5df4b6e287521254399f", + "support" + ], + "remote-playback/cancel-watch-availability.html": [ + "f74aa07eec9e1e47915a7165518429c78c9af28a", + "testharness" + ], + "remote-playback/disable-remote-playback-cancel-watch-availability-throws.html": [ + "3e58b314ce06d2070036930f08147fece491d877", + "testharness" + ], + "remote-playback/disable-remote-playback-prompt-throws.html": [ + "d61b27d43d1f01f4964be312ad38f249bc89c05e", + "testharness" + ], + "remote-playback/disable-remote-playback-watch-availability-throws.html": [ + "2779fd2a3bd27a011e8ba20dd6fb214978d8a54c", + "testharness" + ], + "remote-playback/watch-availability-initial-callback.html": [ + "3d220a3cc0e6a05fbc40c0ab0e46a2e60162b2be", + "testharness" + ], "selection/Document-open-expected.txt": [ "4450a2a693582cf892a9e1b1877250402fbf0ea7", "support" @@ -52639,6 +52758,10 @@ "fcd2a244ad1f12c954c231c479f89beaa3c145e6", "testharness" ], + "service-workers/service-worker/register-link-header.https.html": [ + "fa97635d3a16a0f2a0a0bae8e4b81c8b5100d9cd", + "testharness" + ], "service-workers/service-worker/register-same-scope-different-script-url.https.html": [ "7c32948fe5ff738a38b08ff2d2497ddb63f0a8ef", "testharness" @@ -52987,6 +53110,10 @@ "eaa7fd4f6d2d92af8c27895fc9060296804ece21", "support" ], + "service-workers/service-worker/resources/link-header.py": [ + "5717930bd579b9a63f1b3619195d65b46aa044cf", + "support" + ], "service-workers/service-worker/resources/load_worker.js": [ "08525451705224fd78993adaed33a345d514c9a1", "support" @@ -57316,7 +57443,7 @@ "testharness" ], "workers/semantics/interface-objects/002.worker.js": [ - "b3df65dd764a792ef0a1f8aa7aca24d7fa1ca5e4", + "e067c76ffd47b09d97484a6cbd3d86a29102df9d", "testharness" ], "workers/semantics/interface-objects/003.html": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/check_stability.py b/third_party/WebKit/LayoutTests/external/wpt/check_stability.py index 2d1b8729..a9c7a8fd 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/check_stability.py +++ b/third_party/WebKit/LayoutTests/external/wpt/check_stability.py
@@ -1,7 +1,6 @@ from __future__ import print_function import argparse -import json import logging import os import re @@ -9,13 +8,12 @@ import subprocess import sys import tarfile -import traceback import zipfile +from abc import ABCMeta, abstractmethod from cStringIO import StringIO from collections import defaultdict from ConfigParser import RawConfigParser from io import BytesIO -from urlparse import urljoin from tools.manifest import manifest import requests @@ -109,126 +107,27 @@ print("travis_fold:end:%s" % self.name, file=sys.stderr) -class GitHub(object): - - """Interface for the GitHub API.""" - - def __init__(self, org, repo, token, product): - """Set properties required for communicating with GH API on self.""" - self.token = token - self.headers = {"Accept": "application/vnd.github.v3+json"} - self.auth = (self.token, "x-oauth-basic") - self.org = org - self.repo = repo - self.base_url = "https://api.github.com/repos/%s/%s/" % (org, repo) - self.product = product - - def _headers(self, headers): - """Extend existing HTTP headers and return new value.""" - if headers is None: - headers = {} - rv = self.headers.copy() - rv.update(headers) - return rv - - def post(self, url, data, headers=None): - """Serialize and POST data to given URL.""" - logger.debug("POST %s" % url) - if data is not None: - data = json.dumps(data) - resp = requests.post( - url, - data=data, - headers=self._headers(headers), - auth=self.auth - ) - resp.raise_for_status() - return resp - - def patch(self, url, data, headers=None): - """Serialize and PATCH data to given URL.""" - logger.debug("PATCH %s" % url) - if data is not None: - data = json.dumps(data) - resp = requests.patch( - url, - data=data, - headers=self._headers(headers), - auth=self.auth - ) - resp.raise_for_status() - return resp - - def get(self, url, headers=None): - """Execute GET request for given URL.""" - logger.debug("GET %s" % url) - resp = requests.get( - url, - headers=self._headers(headers), - auth=self.auth - ) - resp.raise_for_status() - return resp - - def post_comment(self, issue_number, body): - """Create or update comment in appropriate GitHub pull request comments.""" - user = self.get(urljoin(self.base_url, "/user")).json() - issue_comments_url = urljoin(self.base_url, "issues/%s/comments" % issue_number) - comments = self.get(issue_comments_url).json() - title_line = format_comment_title(self.product) - data = {"body": body} - for comment in comments: - if (comment["user"]["login"] == user["login"] and - comment["body"].startswith(title_line)): - comment_url = urljoin(self.base_url, "issues/comments/%s" % comment["id"]) - self.patch(comment_url, data) - break - else: - self.post(issue_comments_url, data) - - -class GitHubCommentHandler(logging.Handler): - - """GitHub pull request comment handler. - - Subclasses logging.Handler to add ability to post comments to GitHub. - """ - - def __init__(self, github, pull_number): - """Extend logging.Handler and set required properties on self.""" - logging.Handler.__init__(self) - self.github = github - self.pull_number = pull_number - self.log_data = [] - - def emit(self, record): - """Format record and add to log""" - try: - msg = self.format(record) - self.log_data.append(msg) - except Exception: - self.handleError(record) - - def send(self): - """Post log to GitHub and flush log.""" - self.github.post_comment(self.pull_number, "\n".join(self.log_data)) - self.log_data = [] - - class Browser(object): + __metaclass__ = ABCMeta - """Base browser class that sets a reference to a GitHub token.""" + @abstractmethod + def install(self): + return NotImplemented - product = None - binary = None + @abstractmethod + def install_webdriver(self): + return NotImplemented - def __init__(self, github_token): - """Set GitHub token property on self.""" - self.github_token = github_token + @abstractmethod + def version(self): + return NotImplemented + + @abstractmethod + def wptrunner_args(self): + return NotImplemented class Firefox(Browser): - """Firefox-specific interface. Includes installation, webdriver installation, and wptrunner setup methods. @@ -400,28 +299,6 @@ os.chmod(info.filename, perm) -def setup_github_logging(args): - """Set up and return GitHub comment handler. - - :param args: the parsed arguments passed to the script - """ - gh_handler = None - if args.comment_pr: - github = GitHub(args.user, "web-platform-tests", args.gh_token, args.product) - try: - pr_number = int(args.comment_pr) - except ValueError: - pass - else: - gh_handler = GitHubCommentHandler(github, pr_number) - gh_handler.setLevel(logging.INFO) - logger.debug("Setting up GitHub logging") - logger.addHandler(gh_handler) - else: - logger.warning("No PR number found; not posting to GitHub") - return gh_handler - - class pwd(object): """Create context for temporarily changing present working directory.""" def __init__(self, dir): @@ -695,10 +572,6 @@ default=10, type=int, help="Number of times to run tests") - parser.add_argument("--gh-token", - action="store", - default=os.environ.get("GH_TOKEN"), - help="OAuth token to use for accessing GitHub api") parser.add_argument("--comment-pr", action="store", default=os.environ.get("TRAVIS_PULL_REQUEST"), @@ -733,12 +606,6 @@ os.chdir(args.root) - if args.gh_token: - gh_handler = setup_github_logging(args) - else: - logger.warning("Can't log to GitHub") - gh_handler = None - browser_name = args.product.split(":")[0] with TravisFold("browser_setup"): @@ -767,7 +634,7 @@ install_wptrunner() do_delayed_imports() - browser = browser_cls(args.gh_token) + browser = browser_cls() browser.install() browser.install_webdriver() @@ -823,11 +690,6 @@ else: logger.info("No tests run.") - try: - if gh_handler: - gh_handler.send() - except Exception: - logger.error(traceback.format_exc()) return retcode
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/events/Event-init-while-dispatching-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/events/Event-init-while-dispatching-expected.txt deleted file mode 100644 index 53f0a8e..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/dom/events/Event-init-while-dispatching-expected.txt +++ /dev/null
@@ -1,8 +0,0 @@ -This is a testharness.js-based test. -PASS Calling initKeyboardEvent while dispatching. -PASS Calling initMouseEvent while dispatching. -FAIL Calling initCustomEvent while dispatching. assert_equals: initCustomEvent detail setter should short-circuit expected (object) null but got (number) 1 -PASS Calling initUIEvent while dispatching. -PASS Calling initEvent while dispatching. -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/interfaces-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/interfaces-expected.txt index a9e23107..13dfa2f 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/dom/interfaces-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/dom/interfaces-expected.txt
@@ -145,7 +145,7 @@ PASS MutationObserver interface object name FAIL MutationObserver interface: existence and properties of interface prototype object assert_equals: class string of MutationObserver.prototype expected "[object MutationObserverPrototype]" but got "[object MutationObserver]" PASS MutationObserver interface: existence and properties of interface prototype object's "constructor" property -FAIL MutationObserver interface: operation observe(Node,MutationObserverInit) assert_equals: property has wrong .length expected 1 but got 2 +PASS MutationObserver interface: operation observe(Node,MutationObserverInit) PASS MutationObserver interface: operation disconnect() PASS MutationObserver interface: operation takeRecords() PASS MutationRecord interface: existence and properties of interface object
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/MutationObserver-childList-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/MutationObserver-childList-expected.txt new file mode 100644 index 0000000..a889c6d --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/MutationObserver-childList-expected.txt
@@ -0,0 +1,41 @@ +This is a testharness.js-based test. +PASS childList Node.nodeValue: no mutation +PASS childList Node.textContent: replace content mutation +PASS childList Node.textContent: no previous content mutation +PASS childList Node.textContent: textContent no mutation +PASS childList Node.textContent: empty string mutation +PASS childList Node.normalize mutation +PASS childList Node.normalize mutations +PASS childList Node.insertBefore: addition mutation +PASS childList Node.insertBefore: removal mutation +PASS childList Node.insertBefore: removal and addition mutations +PASS childList Node.insertBefore: fragment addition mutations +PASS childList Node.insertBefore: fragment removal mutations +PASS childList Node.insertBefore: last child addition mutation +PASS childList Node.appendChild: addition mutation +PASS childList Node.appendChild: removal mutation +PASS childList Node.appendChild: removal and addition mutations +PASS childList Node.appendChild: fragment addition mutations +PASS childList Node.appendChild: fragment removal mutations +PASS childList Node.appendChild: addition outside document tree mutation +PASS childList Node.replaceChild: replacement mutation +PASS childList Node.replaceChild: removal mutation +FAIL childList Node.replaceChild: internal replacement mutation assert_equals: mutation records must match expected 2 but got 1 +FAIL childList Node.replaceChild: self internal replacement mutation assert_equals: mutation records must match expected 2 but got 1 +PASS childList Node.removeChild: removal mutation +PASS Range (r70) is created +PASS childList Range.deleteContents: child removal mutation +PASS Range (r71) is created +PASS childList Range.deleteContents: child and data removal mutation +PASS Range (r80) is created +PASS childList Range.extractContents: child removal mutation +PASS Range (r81) is created +PASS childList Range.extractContents: child and data removal mutation +PASS Range (r90) is created +PASS childList Range.insertNode: child insertion mutation +PASS Range (r91) is created +PASS childList Range.insertNode: children insertion mutation +PASS Range (r100) is created +PASS childList Range.surroundContents: children removal and addition mutation +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Node-replaceChild-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Node-replaceChild-expected.txt index 9caa7235..51224a08 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Node-replaceChild-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Node-replaceChild-expected.txt
@@ -2,9 +2,7 @@ PASS Passing null to replaceChild should throw a TypeError. PASS If child's parent is not the context node, a NotFoundError exception should be thrown PASS If the context node is not a node that can contain children, a NotFoundError exception should be thrown -FAIL If node is an inclusive ancestor of the context node, a HierarchyRequestError should be thrown. assert_throws: function "function () { - a.replaceChild(a, a); - }" did not throw +PASS If node is an inclusive ancestor of the context node, a HierarchyRequestError should be thrown. PASS If the context node is a document, inserting a document or text node should throw a HierarchyRequestError. PASS If the context node is a document, inserting a DocumentFragment that contains a text node or too many elements should throw a HierarchyRequestError. PASS If the context node is a document (without element children), inserting a DocumentFragment that contains multiple elements should throw a HierarchyRequestError.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/NodeList-Iterable.html b/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/NodeList-Iterable.html index ef29320..fcbee175 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/NodeList-Iterable.html +++ b/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/NodeList-Iterable.html
@@ -42,15 +42,15 @@ }, 'NodeList responds to Object.keys correctly'); test(function() { - const container = document.getElementById('live'); - const nodeList = container.childNodes; + var container = document.getElementById('live'); + var nodeList = container.childNodes; - let ids = []; - for (const el of nodeList) { + var ids = []; + for (var el of nodeList) { ids.push(el.id); assert_equals(el.localName, 'b'); if (ids.length < 3) { - const newEl = document.createElement('b'); + var newEl = document.createElement('b'); newEl.id = 'after' + el.id; container.appendChild(newEl); }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/ranges/Range-mutations-appendChild-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/ranges/Range-mutations-appendChild-expected.txt deleted file mode 100644 index 310cc6d..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/dom/ranges/Range-mutations-appendChild-expected.txt +++ /dev/null
@@ -1,85 +0,0 @@ -CONSOLE ERROR: line 126: The given range isn't in document. -CONSOLE ERROR: line 126: The given range isn't in document. -CONSOLE ERROR: line 126: The given range isn't in document. -CONSOLE ERROR: line 126: The given range isn't in document. -CONSOLE ERROR: line 126: The given range isn't in document. -CONSOLE ERROR: line 126: The given range isn't in document. -CONSOLE ERROR: line 126: The given range isn't in document. -CONSOLE ERROR: line 126: The given range isn't in document. -CONSOLE ERROR: line 126: The given range isn't in document. -This is a testharness.js-based test. -FAIL testDiv.appendChild(testDiv.lastChild), with unselected range collapsed at (testDiv.lastChild, 0) assert_equals: Wrong start container expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p><p id="b" s... but got Comment node <!--Alphabet soup?--> -PASS testDiv.appendChild(testDiv.lastChild), with selected range collapsed at (testDiv.lastChild, 0) -FAIL testDiv.appendChild(testDiv.lastChild), with unselected range on testDiv.lastChild from 0 to 1 assert_equals: Wrong start container expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p><p id="b" s... but got Comment node <!--Alphabet soup?--> -FAIL testDiv.appendChild(testDiv.lastChild), with selected range on testDiv.lastChild from 0 to 1 assert_equals: Wrong end offset expected 5 but got 6 -FAIL testDiv.appendChild(testDiv.lastChild), with unselected range collapsed at (testDiv.lastChild, 1) assert_equals: Wrong start container expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p><p id="b" s... but got Comment node <!--Alphabet soup?--> -FAIL testDiv.appendChild(testDiv.lastChild), with selected range collapsed at (testDiv.lastChild, 1) assert_equals: Wrong start offset expected 5 but got 6 -FAIL testDiv.appendChild(testDiv.lastChild), with unselected range on testDiv from testDiv.childNodes.length - 2 to testDiv.childNodes.length assert_equals: Wrong end offset expected 5 but got 6 -FAIL testDiv.appendChild(testDiv.lastChild), with selected range on testDiv from testDiv.childNodes.length - 2 to testDiv.childNodes.length assert_equals: Wrong end offset expected 5 but got 6 -PASS testDiv.appendChild(testDiv.lastChild), with unselected range on testDiv from testDiv.childNodes.length - 2 to testDiv.childNodes.length - 1 -PASS testDiv.appendChild(testDiv.lastChild), with selected range on testDiv from testDiv.childNodes.length - 2 to testDiv.childNodes.length - 1 -FAIL testDiv.appendChild(testDiv.lastChild), with unselected range on testDiv from testDiv.childNodes.length - 1 to testDiv.childNodes.length assert_equals: Wrong end offset expected 5 but got 6 -FAIL testDiv.appendChild(testDiv.lastChild), with selected range on testDiv from testDiv.childNodes.length - 1 to testDiv.childNodes.length assert_equals: Wrong end offset expected 5 but got 6 -PASS testDiv.appendChild(testDiv.lastChild), with unselected range collapsed at (testDiv, testDiv.childNodes.length - 1) -PASS testDiv.appendChild(testDiv.lastChild), with selected range collapsed at (testDiv, testDiv.childNodes.length - 1) -FAIL testDiv.appendChild(testDiv.lastChild), with unselected range collapsed at (testDiv, testDiv.childNodes.length) assert_equals: Wrong start offset expected 5 but got 6 -FAIL testDiv.appendChild(testDiv.lastChild), with selected range collapsed at (testDiv, testDiv.childNodes.length) assert_equals: Wrong start offset expected 5 but got 6 -FAIL detachedDiv.appendChild(detachedDiv.lastChild), with unselected range collapsed at (detachedDiv.lastChild, 0) assert_equals: Wrong start container expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Element node <p>Wxyzabcd</p> -PASS detachedDiv.appendChild(detachedDiv.lastChild), with selected range collapsed at (detachedDiv.lastChild, 0) -FAIL detachedDiv.appendChild(detachedDiv.lastChild), with unselected range on detachedDiv.lastChild from 0 to 1 assert_equals: Wrong start container expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Element node <p>Wxyzabcd</p> -PASS detachedDiv.appendChild(detachedDiv.lastChild), with selected range on detachedDiv.lastChild from 0 to 1 -FAIL detachedDiv.appendChild(detachedDiv.lastChild), with unselected range collapsed at (detachedDiv.lastChild, 1) assert_equals: Wrong start container expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Element node <p>Wxyzabcd</p> -PASS detachedDiv.appendChild(detachedDiv.lastChild), with selected range collapsed at (detachedDiv.lastChild, 1) -FAIL detachedDiv.appendChild(detachedDiv.lastChild), with unselected range on detachedDiv from detachedDiv.childNodes.length - 2 to detachedDiv.childNodes.length assert_equals: Wrong end offset expected 1 but got 2 -PASS detachedDiv.appendChild(detachedDiv.lastChild), with selected range on detachedDiv from detachedDiv.childNodes.length - 2 to detachedDiv.childNodes.length -PASS detachedDiv.appendChild(detachedDiv.lastChild), with unselected range on detachedDiv from detachedDiv.childNodes.length - 2 to detachedDiv.childNodes.length - 1 -PASS detachedDiv.appendChild(detachedDiv.lastChild), with selected range on detachedDiv from detachedDiv.childNodes.length - 2 to detachedDiv.childNodes.length - 1 -FAIL detachedDiv.appendChild(detachedDiv.lastChild), with unselected range on detachedDiv from detachedDiv.childNodes.length - 1 to detachedDiv.childNodes.length assert_equals: Wrong end offset expected 1 but got 2 -PASS detachedDiv.appendChild(detachedDiv.lastChild), with selected range on detachedDiv from detachedDiv.childNodes.length - 1 to detachedDiv.childNodes.length -PASS detachedDiv.appendChild(detachedDiv.lastChild), with unselected range collapsed at (detachedDiv, detachedDiv.childNodes.length - 1) -PASS detachedDiv.appendChild(detachedDiv.lastChild), with selected range collapsed at (detachedDiv, detachedDiv.childNodes.length - 1) -FAIL detachedDiv.appendChild(detachedDiv.lastChild), with unselected range collapsed at (detachedDiv, detachedDiv.childNodes.length) assert_equals: Wrong start offset expected 1 but got 2 -PASS detachedDiv.appendChild(detachedDiv.lastChild), with selected range collapsed at (detachedDiv, detachedDiv.childNodes.length) -PASS paras[0].appendChild(paras[1]), with unselected range collapsed at (paras[0], 0) -PASS paras[0].appendChild(paras[1]), with selected range collapsed at (paras[0], 0) -PASS paras[0].appendChild(paras[1]), with unselected range on paras[0] from 0 to 1 -PASS paras[0].appendChild(paras[1]), with selected range on paras[0] from 0 to 1 -PASS paras[0].appendChild(paras[1]), with unselected range collapsed at (paras[0], 1) -PASS paras[0].appendChild(paras[1]), with selected range collapsed at (paras[0], 1) -PASS paras[0].appendChild(paras[1]), with unselected range on testDiv from 0 to 1 -PASS paras[0].appendChild(paras[1]), with selected range on testDiv from 0 to 1 -PASS paras[0].appendChild(paras[1]), with unselected range on testDiv from 0 to 2 -PASS paras[0].appendChild(paras[1]), with selected range on testDiv from 0 to 2 -PASS paras[0].appendChild(paras[1]), with unselected range collapsed at (testDiv, 1) -PASS paras[0].appendChild(paras[1]), with selected range collapsed at (testDiv, 1) -PASS paras[0].appendChild(paras[1]), with unselected range on testDiv from 1 to 2 -PASS paras[0].appendChild(paras[1]), with selected range on testDiv from 1 to 2 -PASS foreignDoc.appendChild(detachedComment), with unselected range on foreignDoc from foreignDoc.childNodes.length - 1 to foreignDoc.childNodes.length -PASS foreignDoc.appendChild(detachedComment), with selected range on foreignDoc from foreignDoc.childNodes.length - 1 to foreignDoc.childNodes.length -PASS foreignDoc.appendChild(detachedComment), with unselected range collapsed at (foreignDoc, foreignDoc.childNodes.length - 1) -PASS foreignDoc.appendChild(detachedComment), with selected range collapsed at (foreignDoc, foreignDoc.childNodes.length - 1) -PASS foreignDoc.appendChild(detachedComment), with unselected range collapsed at (foreignDoc, foreignDoc.childNodes.length) -PASS foreignDoc.appendChild(detachedComment), with selected range collapsed at (foreignDoc, foreignDoc.childNodes.length) -PASS foreignDoc.appendChild(detachedComment), with unselected range on detachedComment from 0 to 5 -PASS foreignDoc.appendChild(detachedComment), with selected range on detachedComment from 0 to 5 -PASS paras[0].appendChild(xmlTextNode), with unselected range collapsed at (paras[0], 0) -PASS paras[0].appendChild(xmlTextNode), with selected range collapsed at (paras[0], 0) -PASS paras[0].appendChild(xmlTextNode), with unselected range on paras[0] from 0 to 1 -PASS paras[0].appendChild(xmlTextNode), with selected range on paras[0] from 0 to 1 -PASS paras[0].appendChild(xmlTextNode), with unselected range collapsed at (paras[0], 1) -PASS paras[0].appendChild(xmlTextNode), with selected range collapsed at (paras[0], 1) -PASS paras[0].appendChild(paras[0]), with unselected range on paras[0] from 0 to 1 -PASS paras[0].appendChild(paras[0]), with selected range on paras[0] from 0 to 1 -PASS paras[0].appendChild(testDiv), with unselected range on paras[0] from 0 to 1 -PASS paras[0].appendChild(testDiv), with selected range on paras[0] from 0 to 1 -PASS paras[0].appendChild(document), with unselected range on paras[0] from 0 to 1 -PASS paras[0].appendChild(document), with selected range on paras[0] from 0 to 1 -PASS paras[0].appendChild(foreignDoc), with unselected range on paras[0] from 0 to 1 -PASS paras[0].appendChild(foreignDoc), with selected range on paras[0] from 0 to 1 -PASS paras[0].appendChild(document.doctype), with unselected range on paras[0] from 0 to 1 -PASS paras[0].appendChild(document.doctype), with selected range on paras[0] from 0 to 1 -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/ranges/Range-mutations-dataChange-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/ranges/Range-mutations-dataChange-expected.txt index 3f90db5..2e9592dc 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/dom/ranges/Range-mutations-dataChange-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/dom/ranges/Range-mutations-dataChange-expected.txt
@@ -255,10 +255,10 @@ PASS paras[0].firstChild.data = "", with selected range on paras[0].firstChild from 0 to 1 PASS paras[0].firstChild.data = "foo", with unselected range on paras[0].firstChild from 0 to 1 PASS paras[0].firstChild.data = "foo", with selected range on paras[0].firstChild from 0 to 1 -FAIL paras[0].firstChild.data = paras[0].firstChild.data, with unselected range on paras[0].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 -FAIL paras[0].firstChild.data = paras[0].firstChild.data, with selected range on paras[0].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 -FAIL paras[0].firstChild.data += "", with unselected range on paras[0].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 -FAIL paras[0].firstChild.data += "", with selected range on paras[0].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS paras[0].firstChild.data = paras[0].firstChild.data, with unselected range on paras[0].firstChild from 0 to 1 +PASS paras[0].firstChild.data = paras[0].firstChild.data, with selected range on paras[0].firstChild from 0 to 1 +PASS paras[0].firstChild.data += "", with unselected range on paras[0].firstChild from 0 to 1 +PASS paras[0].firstChild.data += "", with selected range on paras[0].firstChild from 0 to 1 PASS paras[0].firstChild.data += "foo", with unselected range on paras[0].firstChild from 0 to 1 PASS paras[0].firstChild.data += "foo", with selected range on paras[0].firstChild from 0 to 1 PASS paras[0].firstChild.data += paras[0].firstChild.data, with unselected range on paras[0].firstChild from 0 to 1 @@ -267,10 +267,10 @@ PASS paras[0].firstChild.textContent = "", with selected range on paras[0].firstChild from 0 to 1 PASS paras[0].firstChild.textContent = "foo", with unselected range on paras[0].firstChild from 0 to 1 PASS paras[0].firstChild.textContent = "foo", with selected range on paras[0].firstChild from 0 to 1 -FAIL paras[0].firstChild.textContent = paras[0].firstChild.textContent, with unselected range on paras[0].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 -FAIL paras[0].firstChild.textContent = paras[0].firstChild.textContent, with selected range on paras[0].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 -FAIL paras[0].firstChild.textContent += "", with unselected range on paras[0].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 -FAIL paras[0].firstChild.textContent += "", with selected range on paras[0].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS paras[0].firstChild.textContent = paras[0].firstChild.textContent, with unselected range on paras[0].firstChild from 0 to 1 +PASS paras[0].firstChild.textContent = paras[0].firstChild.textContent, with selected range on paras[0].firstChild from 0 to 1 +PASS paras[0].firstChild.textContent += "", with unselected range on paras[0].firstChild from 0 to 1 +PASS paras[0].firstChild.textContent += "", with selected range on paras[0].firstChild from 0 to 1 PASS paras[0].firstChild.textContent += "foo", with unselected range on paras[0].firstChild from 0 to 1 PASS paras[0].firstChild.textContent += "foo", with selected range on paras[0].firstChild from 0 to 1 PASS paras[0].firstChild.textContent += paras[0].firstChild.textContent, with unselected range on paras[0].firstChild from 0 to 1 @@ -279,10 +279,10 @@ PASS paras[0].firstChild.nodeValue = "", with selected range on paras[0].firstChild from 0 to 1 PASS paras[0].firstChild.nodeValue = "foo", with unselected range on paras[0].firstChild from 0 to 1 PASS paras[0].firstChild.nodeValue = "foo", with selected range on paras[0].firstChild from 0 to 1 -FAIL paras[0].firstChild.nodeValue = paras[0].firstChild.nodeValue, with unselected range on paras[0].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 -FAIL paras[0].firstChild.nodeValue = paras[0].firstChild.nodeValue, with selected range on paras[0].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 -FAIL paras[0].firstChild.nodeValue += "", with unselected range on paras[0].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 -FAIL paras[0].firstChild.nodeValue += "", with selected range on paras[0].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS paras[0].firstChild.nodeValue = paras[0].firstChild.nodeValue, with unselected range on paras[0].firstChild from 0 to 1 +PASS paras[0].firstChild.nodeValue = paras[0].firstChild.nodeValue, with selected range on paras[0].firstChild from 0 to 1 +PASS paras[0].firstChild.nodeValue += "", with unselected range on paras[0].firstChild from 0 to 1 +PASS paras[0].firstChild.nodeValue += "", with selected range on paras[0].firstChild from 0 to 1 PASS paras[0].firstChild.nodeValue += "foo", with unselected range on paras[0].firstChild from 0 to 1 PASS paras[0].firstChild.nodeValue += "foo", with selected range on paras[0].firstChild from 0 to 1 PASS paras[0].firstChild.nodeValue += paras[0].firstChild.nodeValue, with unselected range on paras[0].firstChild from 0 to 1 @@ -291,10 +291,10 @@ PASS paras[0].firstChild.data = "", with selected range collapsed at (paras[0].firstChild, 1) PASS paras[0].firstChild.data = "foo", with unselected range collapsed at (paras[0].firstChild, 1) PASS paras[0].firstChild.data = "foo", with selected range collapsed at (paras[0].firstChild, 1) -FAIL paras[0].firstChild.data = paras[0].firstChild.data, with unselected range collapsed at (paras[0].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[0].firstChild.data = paras[0].firstChild.data, with selected range collapsed at (paras[0].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[0].firstChild.data += "", with unselected range collapsed at (paras[0].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[0].firstChild.data += "", with selected range collapsed at (paras[0].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS paras[0].firstChild.data = paras[0].firstChild.data, with unselected range collapsed at (paras[0].firstChild, 1) +PASS paras[0].firstChild.data = paras[0].firstChild.data, with selected range collapsed at (paras[0].firstChild, 1) +PASS paras[0].firstChild.data += "", with unselected range collapsed at (paras[0].firstChild, 1) +PASS paras[0].firstChild.data += "", with selected range collapsed at (paras[0].firstChild, 1) PASS paras[0].firstChild.data += "foo", with unselected range collapsed at (paras[0].firstChild, 1) PASS paras[0].firstChild.data += "foo", with selected range collapsed at (paras[0].firstChild, 1) PASS paras[0].firstChild.data += paras[0].firstChild.data, with unselected range collapsed at (paras[0].firstChild, 1) @@ -303,10 +303,10 @@ PASS paras[0].firstChild.textContent = "", with selected range collapsed at (paras[0].firstChild, 1) PASS paras[0].firstChild.textContent = "foo", with unselected range collapsed at (paras[0].firstChild, 1) PASS paras[0].firstChild.textContent = "foo", with selected range collapsed at (paras[0].firstChild, 1) -FAIL paras[0].firstChild.textContent = paras[0].firstChild.textContent, with unselected range collapsed at (paras[0].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[0].firstChild.textContent = paras[0].firstChild.textContent, with selected range collapsed at (paras[0].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[0].firstChild.textContent += "", with unselected range collapsed at (paras[0].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[0].firstChild.textContent += "", with selected range collapsed at (paras[0].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS paras[0].firstChild.textContent = paras[0].firstChild.textContent, with unselected range collapsed at (paras[0].firstChild, 1) +PASS paras[0].firstChild.textContent = paras[0].firstChild.textContent, with selected range collapsed at (paras[0].firstChild, 1) +PASS paras[0].firstChild.textContent += "", with unselected range collapsed at (paras[0].firstChild, 1) +PASS paras[0].firstChild.textContent += "", with selected range collapsed at (paras[0].firstChild, 1) PASS paras[0].firstChild.textContent += "foo", with unselected range collapsed at (paras[0].firstChild, 1) PASS paras[0].firstChild.textContent += "foo", with selected range collapsed at (paras[0].firstChild, 1) PASS paras[0].firstChild.textContent += paras[0].firstChild.textContent, with unselected range collapsed at (paras[0].firstChild, 1) @@ -315,10 +315,10 @@ PASS paras[0].firstChild.nodeValue = "", with selected range collapsed at (paras[0].firstChild, 1) PASS paras[0].firstChild.nodeValue = "foo", with unselected range collapsed at (paras[0].firstChild, 1) PASS paras[0].firstChild.nodeValue = "foo", with selected range collapsed at (paras[0].firstChild, 1) -FAIL paras[0].firstChild.nodeValue = paras[0].firstChild.nodeValue, with unselected range collapsed at (paras[0].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[0].firstChild.nodeValue = paras[0].firstChild.nodeValue, with selected range collapsed at (paras[0].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[0].firstChild.nodeValue += "", with unselected range collapsed at (paras[0].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[0].firstChild.nodeValue += "", with selected range collapsed at (paras[0].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS paras[0].firstChild.nodeValue = paras[0].firstChild.nodeValue, with unselected range collapsed at (paras[0].firstChild, 1) +PASS paras[0].firstChild.nodeValue = paras[0].firstChild.nodeValue, with selected range collapsed at (paras[0].firstChild, 1) +PASS paras[0].firstChild.nodeValue += "", with unselected range collapsed at (paras[0].firstChild, 1) +PASS paras[0].firstChild.nodeValue += "", with selected range collapsed at (paras[0].firstChild, 1) PASS paras[0].firstChild.nodeValue += "foo", with unselected range collapsed at (paras[0].firstChild, 1) PASS paras[0].firstChild.nodeValue += "foo", with selected range collapsed at (paras[0].firstChild, 1) PASS paras[0].firstChild.nodeValue += paras[0].firstChild.nodeValue, with unselected range collapsed at (paras[0].firstChild, 1) @@ -327,10 +327,10 @@ PASS paras[0].firstChild.data = "", with selected range on paras[0].firstChild from 0 to paras[0].firstChild.length PASS paras[0].firstChild.data = "foo", with unselected range on paras[0].firstChild from 0 to paras[0].firstChild.length PASS paras[0].firstChild.data = "foo", with selected range on paras[0].firstChild from 0 to paras[0].firstChild.length -FAIL paras[0].firstChild.data = paras[0].firstChild.data, with unselected range on paras[0].firstChild from 0 to paras[0].firstChild.length assert_equals: Wrong end offset expected 0 but got 17 -FAIL paras[0].firstChild.data = paras[0].firstChild.data, with selected range on paras[0].firstChild from 0 to paras[0].firstChild.length assert_equals: Wrong end offset expected 0 but got 17 -FAIL paras[0].firstChild.data += "", with unselected range on paras[0].firstChild from 0 to paras[0].firstChild.length assert_equals: Wrong end offset expected 0 but got 17 -FAIL paras[0].firstChild.data += "", with selected range on paras[0].firstChild from 0 to paras[0].firstChild.length assert_equals: Wrong end offset expected 0 but got 17 +PASS paras[0].firstChild.data = paras[0].firstChild.data, with unselected range on paras[0].firstChild from 0 to paras[0].firstChild.length +PASS paras[0].firstChild.data = paras[0].firstChild.data, with selected range on paras[0].firstChild from 0 to paras[0].firstChild.length +PASS paras[0].firstChild.data += "", with unselected range on paras[0].firstChild from 0 to paras[0].firstChild.length +PASS paras[0].firstChild.data += "", with selected range on paras[0].firstChild from 0 to paras[0].firstChild.length PASS paras[0].firstChild.data += "foo", with unselected range on paras[0].firstChild from 0 to paras[0].firstChild.length PASS paras[0].firstChild.data += "foo", with selected range on paras[0].firstChild from 0 to paras[0].firstChild.length PASS paras[0].firstChild.data += paras[0].firstChild.data, with unselected range on paras[0].firstChild from 0 to paras[0].firstChild.length @@ -339,10 +339,10 @@ PASS paras[0].firstChild.textContent = "", with selected range on paras[0].firstChild from 0 to paras[0].firstChild.length PASS paras[0].firstChild.textContent = "foo", with unselected range on paras[0].firstChild from 0 to paras[0].firstChild.length PASS paras[0].firstChild.textContent = "foo", with selected range on paras[0].firstChild from 0 to paras[0].firstChild.length -FAIL paras[0].firstChild.textContent = paras[0].firstChild.textContent, with unselected range on paras[0].firstChild from 0 to paras[0].firstChild.length assert_equals: Wrong end offset expected 0 but got 17 -FAIL paras[0].firstChild.textContent = paras[0].firstChild.textContent, with selected range on paras[0].firstChild from 0 to paras[0].firstChild.length assert_equals: Wrong end offset expected 0 but got 17 -FAIL paras[0].firstChild.textContent += "", with unselected range on paras[0].firstChild from 0 to paras[0].firstChild.length assert_equals: Wrong end offset expected 0 but got 17 -FAIL paras[0].firstChild.textContent += "", with selected range on paras[0].firstChild from 0 to paras[0].firstChild.length assert_equals: Wrong end offset expected 0 but got 17 +PASS paras[0].firstChild.textContent = paras[0].firstChild.textContent, with unselected range on paras[0].firstChild from 0 to paras[0].firstChild.length +PASS paras[0].firstChild.textContent = paras[0].firstChild.textContent, with selected range on paras[0].firstChild from 0 to paras[0].firstChild.length +PASS paras[0].firstChild.textContent += "", with unselected range on paras[0].firstChild from 0 to paras[0].firstChild.length +PASS paras[0].firstChild.textContent += "", with selected range on paras[0].firstChild from 0 to paras[0].firstChild.length PASS paras[0].firstChild.textContent += "foo", with unselected range on paras[0].firstChild from 0 to paras[0].firstChild.length PASS paras[0].firstChild.textContent += "foo", with selected range on paras[0].firstChild from 0 to paras[0].firstChild.length PASS paras[0].firstChild.textContent += paras[0].firstChild.textContent, with unselected range on paras[0].firstChild from 0 to paras[0].firstChild.length @@ -351,10 +351,10 @@ PASS paras[0].firstChild.nodeValue = "", with selected range on paras[0].firstChild from 0 to paras[0].firstChild.length PASS paras[0].firstChild.nodeValue = "foo", with unselected range on paras[0].firstChild from 0 to paras[0].firstChild.length PASS paras[0].firstChild.nodeValue = "foo", with selected range on paras[0].firstChild from 0 to paras[0].firstChild.length -FAIL paras[0].firstChild.nodeValue = paras[0].firstChild.nodeValue, with unselected range on paras[0].firstChild from 0 to paras[0].firstChild.length assert_equals: Wrong end offset expected 0 but got 17 -FAIL paras[0].firstChild.nodeValue = paras[0].firstChild.nodeValue, with selected range on paras[0].firstChild from 0 to paras[0].firstChild.length assert_equals: Wrong end offset expected 0 but got 17 -FAIL paras[0].firstChild.nodeValue += "", with unselected range on paras[0].firstChild from 0 to paras[0].firstChild.length assert_equals: Wrong end offset expected 0 but got 17 -FAIL paras[0].firstChild.nodeValue += "", with selected range on paras[0].firstChild from 0 to paras[0].firstChild.length assert_equals: Wrong end offset expected 0 but got 17 +PASS paras[0].firstChild.nodeValue = paras[0].firstChild.nodeValue, with unselected range on paras[0].firstChild from 0 to paras[0].firstChild.length +PASS paras[0].firstChild.nodeValue = paras[0].firstChild.nodeValue, with selected range on paras[0].firstChild from 0 to paras[0].firstChild.length +PASS paras[0].firstChild.nodeValue += "", with unselected range on paras[0].firstChild from 0 to paras[0].firstChild.length +PASS paras[0].firstChild.nodeValue += "", with selected range on paras[0].firstChild from 0 to paras[0].firstChild.length PASS paras[0].firstChild.nodeValue += "foo", with unselected range on paras[0].firstChild from 0 to paras[0].firstChild.length PASS paras[0].firstChild.nodeValue += "foo", with selected range on paras[0].firstChild from 0 to paras[0].firstChild.length PASS paras[0].firstChild.nodeValue += paras[0].firstChild.nodeValue, with unselected range on paras[0].firstChild from 0 to paras[0].firstChild.length @@ -363,10 +363,10 @@ PASS paras[0].firstChild.data = "", with selected range on paras[0].firstChild from 1 to paras[0].firstChild.length PASS paras[0].firstChild.data = "foo", with unselected range on paras[0].firstChild from 1 to paras[0].firstChild.length PASS paras[0].firstChild.data = "foo", with selected range on paras[0].firstChild from 1 to paras[0].firstChild.length -FAIL paras[0].firstChild.data = paras[0].firstChild.data, with unselected range on paras[0].firstChild from 1 to paras[0].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[0].firstChild.data = paras[0].firstChild.data, with selected range on paras[0].firstChild from 1 to paras[0].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[0].firstChild.data += "", with unselected range on paras[0].firstChild from 1 to paras[0].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[0].firstChild.data += "", with selected range on paras[0].firstChild from 1 to paras[0].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 +PASS paras[0].firstChild.data = paras[0].firstChild.data, with unselected range on paras[0].firstChild from 1 to paras[0].firstChild.length +PASS paras[0].firstChild.data = paras[0].firstChild.data, with selected range on paras[0].firstChild from 1 to paras[0].firstChild.length +PASS paras[0].firstChild.data += "", with unselected range on paras[0].firstChild from 1 to paras[0].firstChild.length +PASS paras[0].firstChild.data += "", with selected range on paras[0].firstChild from 1 to paras[0].firstChild.length PASS paras[0].firstChild.data += "foo", with unselected range on paras[0].firstChild from 1 to paras[0].firstChild.length PASS paras[0].firstChild.data += "foo", with selected range on paras[0].firstChild from 1 to paras[0].firstChild.length PASS paras[0].firstChild.data += paras[0].firstChild.data, with unselected range on paras[0].firstChild from 1 to paras[0].firstChild.length @@ -375,10 +375,10 @@ PASS paras[0].firstChild.textContent = "", with selected range on paras[0].firstChild from 1 to paras[0].firstChild.length PASS paras[0].firstChild.textContent = "foo", with unselected range on paras[0].firstChild from 1 to paras[0].firstChild.length PASS paras[0].firstChild.textContent = "foo", with selected range on paras[0].firstChild from 1 to paras[0].firstChild.length -FAIL paras[0].firstChild.textContent = paras[0].firstChild.textContent, with unselected range on paras[0].firstChild from 1 to paras[0].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[0].firstChild.textContent = paras[0].firstChild.textContent, with selected range on paras[0].firstChild from 1 to paras[0].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[0].firstChild.textContent += "", with unselected range on paras[0].firstChild from 1 to paras[0].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[0].firstChild.textContent += "", with selected range on paras[0].firstChild from 1 to paras[0].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 +PASS paras[0].firstChild.textContent = paras[0].firstChild.textContent, with unselected range on paras[0].firstChild from 1 to paras[0].firstChild.length +PASS paras[0].firstChild.textContent = paras[0].firstChild.textContent, with selected range on paras[0].firstChild from 1 to paras[0].firstChild.length +PASS paras[0].firstChild.textContent += "", with unselected range on paras[0].firstChild from 1 to paras[0].firstChild.length +PASS paras[0].firstChild.textContent += "", with selected range on paras[0].firstChild from 1 to paras[0].firstChild.length PASS paras[0].firstChild.textContent += "foo", with unselected range on paras[0].firstChild from 1 to paras[0].firstChild.length PASS paras[0].firstChild.textContent += "foo", with selected range on paras[0].firstChild from 1 to paras[0].firstChild.length PASS paras[0].firstChild.textContent += paras[0].firstChild.textContent, with unselected range on paras[0].firstChild from 1 to paras[0].firstChild.length @@ -387,10 +387,10 @@ PASS paras[0].firstChild.nodeValue = "", with selected range on paras[0].firstChild from 1 to paras[0].firstChild.length PASS paras[0].firstChild.nodeValue = "foo", with unselected range on paras[0].firstChild from 1 to paras[0].firstChild.length PASS paras[0].firstChild.nodeValue = "foo", with selected range on paras[0].firstChild from 1 to paras[0].firstChild.length -FAIL paras[0].firstChild.nodeValue = paras[0].firstChild.nodeValue, with unselected range on paras[0].firstChild from 1 to paras[0].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[0].firstChild.nodeValue = paras[0].firstChild.nodeValue, with selected range on paras[0].firstChild from 1 to paras[0].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[0].firstChild.nodeValue += "", with unselected range on paras[0].firstChild from 1 to paras[0].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[0].firstChild.nodeValue += "", with selected range on paras[0].firstChild from 1 to paras[0].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 +PASS paras[0].firstChild.nodeValue = paras[0].firstChild.nodeValue, with unselected range on paras[0].firstChild from 1 to paras[0].firstChild.length +PASS paras[0].firstChild.nodeValue = paras[0].firstChild.nodeValue, with selected range on paras[0].firstChild from 1 to paras[0].firstChild.length +PASS paras[0].firstChild.nodeValue += "", with unselected range on paras[0].firstChild from 1 to paras[0].firstChild.length +PASS paras[0].firstChild.nodeValue += "", with selected range on paras[0].firstChild from 1 to paras[0].firstChild.length PASS paras[0].firstChild.nodeValue += "foo", with unselected range on paras[0].firstChild from 1 to paras[0].firstChild.length PASS paras[0].firstChild.nodeValue += "foo", with selected range on paras[0].firstChild from 1 to paras[0].firstChild.length PASS paras[0].firstChild.nodeValue += paras[0].firstChild.nodeValue, with unselected range on paras[0].firstChild from 1 to paras[0].firstChild.length @@ -399,10 +399,10 @@ PASS paras[0].firstChild.data = "", with selected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) PASS paras[0].firstChild.data = "foo", with unselected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) PASS paras[0].firstChild.data = "foo", with selected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) -FAIL paras[0].firstChild.data = paras[0].firstChild.data, with unselected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) assert_equals: Wrong start offset expected 0 but got 17 -FAIL paras[0].firstChild.data = paras[0].firstChild.data, with selected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) assert_equals: Wrong start offset expected 0 but got 17 -FAIL paras[0].firstChild.data += "", with unselected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) assert_equals: Wrong start offset expected 0 but got 17 -FAIL paras[0].firstChild.data += "", with selected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) assert_equals: Wrong start offset expected 0 but got 17 +PASS paras[0].firstChild.data = paras[0].firstChild.data, with unselected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) +PASS paras[0].firstChild.data = paras[0].firstChild.data, with selected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) +PASS paras[0].firstChild.data += "", with unselected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) +PASS paras[0].firstChild.data += "", with selected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) PASS paras[0].firstChild.data += "foo", with unselected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) PASS paras[0].firstChild.data += "foo", with selected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) PASS paras[0].firstChild.data += paras[0].firstChild.data, with unselected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) @@ -411,10 +411,10 @@ PASS paras[0].firstChild.textContent = "", with selected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) PASS paras[0].firstChild.textContent = "foo", with unselected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) PASS paras[0].firstChild.textContent = "foo", with selected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) -FAIL paras[0].firstChild.textContent = paras[0].firstChild.textContent, with unselected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) assert_equals: Wrong start offset expected 0 but got 17 -FAIL paras[0].firstChild.textContent = paras[0].firstChild.textContent, with selected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) assert_equals: Wrong start offset expected 0 but got 17 -FAIL paras[0].firstChild.textContent += "", with unselected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) assert_equals: Wrong start offset expected 0 but got 17 -FAIL paras[0].firstChild.textContent += "", with selected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) assert_equals: Wrong start offset expected 0 but got 17 +PASS paras[0].firstChild.textContent = paras[0].firstChild.textContent, with unselected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) +PASS paras[0].firstChild.textContent = paras[0].firstChild.textContent, with selected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) +PASS paras[0].firstChild.textContent += "", with unselected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) +PASS paras[0].firstChild.textContent += "", with selected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) PASS paras[0].firstChild.textContent += "foo", with unselected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) PASS paras[0].firstChild.textContent += "foo", with selected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) PASS paras[0].firstChild.textContent += paras[0].firstChild.textContent, with unselected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) @@ -423,10 +423,10 @@ PASS paras[0].firstChild.nodeValue = "", with selected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) PASS paras[0].firstChild.nodeValue = "foo", with unselected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) PASS paras[0].firstChild.nodeValue = "foo", with selected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) -FAIL paras[0].firstChild.nodeValue = paras[0].firstChild.nodeValue, with unselected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) assert_equals: Wrong start offset expected 0 but got 17 -FAIL paras[0].firstChild.nodeValue = paras[0].firstChild.nodeValue, with selected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) assert_equals: Wrong start offset expected 0 but got 17 -FAIL paras[0].firstChild.nodeValue += "", with unselected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) assert_equals: Wrong start offset expected 0 but got 17 -FAIL paras[0].firstChild.nodeValue += "", with selected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) assert_equals: Wrong start offset expected 0 but got 17 +PASS paras[0].firstChild.nodeValue = paras[0].firstChild.nodeValue, with unselected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) +PASS paras[0].firstChild.nodeValue = paras[0].firstChild.nodeValue, with selected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) +PASS paras[0].firstChild.nodeValue += "", with unselected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) +PASS paras[0].firstChild.nodeValue += "", with selected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) PASS paras[0].firstChild.nodeValue += "foo", with unselected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) PASS paras[0].firstChild.nodeValue += "foo", with selected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) PASS paras[0].firstChild.nodeValue += paras[0].firstChild.nodeValue, with unselected range collapsed at (paras[0].firstChild, paras[0].firstChild.length) @@ -471,10 +471,10 @@ PASS paras[1].firstChild.data = "", with selected range on paras[1].firstChild from 0 to 1 PASS paras[1].firstChild.data = "foo", with unselected range on paras[1].firstChild from 0 to 1 PASS paras[1].firstChild.data = "foo", with selected range on paras[1].firstChild from 0 to 1 -FAIL paras[1].firstChild.data = paras[1].firstChild.data, with unselected range on paras[1].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 -FAIL paras[1].firstChild.data = paras[1].firstChild.data, with selected range on paras[1].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 -FAIL paras[1].firstChild.data += "", with unselected range on paras[1].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 -FAIL paras[1].firstChild.data += "", with selected range on paras[1].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS paras[1].firstChild.data = paras[1].firstChild.data, with unselected range on paras[1].firstChild from 0 to 1 +PASS paras[1].firstChild.data = paras[1].firstChild.data, with selected range on paras[1].firstChild from 0 to 1 +PASS paras[1].firstChild.data += "", with unselected range on paras[1].firstChild from 0 to 1 +PASS paras[1].firstChild.data += "", with selected range on paras[1].firstChild from 0 to 1 PASS paras[1].firstChild.data += "foo", with unselected range on paras[1].firstChild from 0 to 1 PASS paras[1].firstChild.data += "foo", with selected range on paras[1].firstChild from 0 to 1 PASS paras[1].firstChild.data += paras[1].firstChild.data, with unselected range on paras[1].firstChild from 0 to 1 @@ -483,10 +483,10 @@ PASS paras[1].firstChild.textContent = "", with selected range on paras[1].firstChild from 0 to 1 PASS paras[1].firstChild.textContent = "foo", with unselected range on paras[1].firstChild from 0 to 1 PASS paras[1].firstChild.textContent = "foo", with selected range on paras[1].firstChild from 0 to 1 -FAIL paras[1].firstChild.textContent = paras[1].firstChild.textContent, with unselected range on paras[1].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 -FAIL paras[1].firstChild.textContent = paras[1].firstChild.textContent, with selected range on paras[1].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 -FAIL paras[1].firstChild.textContent += "", with unselected range on paras[1].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 -FAIL paras[1].firstChild.textContent += "", with selected range on paras[1].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS paras[1].firstChild.textContent = paras[1].firstChild.textContent, with unselected range on paras[1].firstChild from 0 to 1 +PASS paras[1].firstChild.textContent = paras[1].firstChild.textContent, with selected range on paras[1].firstChild from 0 to 1 +PASS paras[1].firstChild.textContent += "", with unselected range on paras[1].firstChild from 0 to 1 +PASS paras[1].firstChild.textContent += "", with selected range on paras[1].firstChild from 0 to 1 PASS paras[1].firstChild.textContent += "foo", with unselected range on paras[1].firstChild from 0 to 1 PASS paras[1].firstChild.textContent += "foo", with selected range on paras[1].firstChild from 0 to 1 PASS paras[1].firstChild.textContent += paras[1].firstChild.textContent, with unselected range on paras[1].firstChild from 0 to 1 @@ -495,10 +495,10 @@ PASS paras[1].firstChild.nodeValue = "", with selected range on paras[1].firstChild from 0 to 1 PASS paras[1].firstChild.nodeValue = "foo", with unselected range on paras[1].firstChild from 0 to 1 PASS paras[1].firstChild.nodeValue = "foo", with selected range on paras[1].firstChild from 0 to 1 -FAIL paras[1].firstChild.nodeValue = paras[1].firstChild.nodeValue, with unselected range on paras[1].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 -FAIL paras[1].firstChild.nodeValue = paras[1].firstChild.nodeValue, with selected range on paras[1].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 -FAIL paras[1].firstChild.nodeValue += "", with unselected range on paras[1].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 -FAIL paras[1].firstChild.nodeValue += "", with selected range on paras[1].firstChild from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS paras[1].firstChild.nodeValue = paras[1].firstChild.nodeValue, with unselected range on paras[1].firstChild from 0 to 1 +PASS paras[1].firstChild.nodeValue = paras[1].firstChild.nodeValue, with selected range on paras[1].firstChild from 0 to 1 +PASS paras[1].firstChild.nodeValue += "", with unselected range on paras[1].firstChild from 0 to 1 +PASS paras[1].firstChild.nodeValue += "", with selected range on paras[1].firstChild from 0 to 1 PASS paras[1].firstChild.nodeValue += "foo", with unselected range on paras[1].firstChild from 0 to 1 PASS paras[1].firstChild.nodeValue += "foo", with selected range on paras[1].firstChild from 0 to 1 PASS paras[1].firstChild.nodeValue += paras[1].firstChild.nodeValue, with unselected range on paras[1].firstChild from 0 to 1 @@ -507,10 +507,10 @@ PASS paras[1].firstChild.data = "", with selected range collapsed at (paras[1].firstChild, 1) PASS paras[1].firstChild.data = "foo", with unselected range collapsed at (paras[1].firstChild, 1) PASS paras[1].firstChild.data = "foo", with selected range collapsed at (paras[1].firstChild, 1) -FAIL paras[1].firstChild.data = paras[1].firstChild.data, with unselected range collapsed at (paras[1].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[1].firstChild.data = paras[1].firstChild.data, with selected range collapsed at (paras[1].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[1].firstChild.data += "", with unselected range collapsed at (paras[1].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[1].firstChild.data += "", with selected range collapsed at (paras[1].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS paras[1].firstChild.data = paras[1].firstChild.data, with unselected range collapsed at (paras[1].firstChild, 1) +PASS paras[1].firstChild.data = paras[1].firstChild.data, with selected range collapsed at (paras[1].firstChild, 1) +PASS paras[1].firstChild.data += "", with unselected range collapsed at (paras[1].firstChild, 1) +PASS paras[1].firstChild.data += "", with selected range collapsed at (paras[1].firstChild, 1) PASS paras[1].firstChild.data += "foo", with unselected range collapsed at (paras[1].firstChild, 1) PASS paras[1].firstChild.data += "foo", with selected range collapsed at (paras[1].firstChild, 1) PASS paras[1].firstChild.data += paras[1].firstChild.data, with unselected range collapsed at (paras[1].firstChild, 1) @@ -519,10 +519,10 @@ PASS paras[1].firstChild.textContent = "", with selected range collapsed at (paras[1].firstChild, 1) PASS paras[1].firstChild.textContent = "foo", with unselected range collapsed at (paras[1].firstChild, 1) PASS paras[1].firstChild.textContent = "foo", with selected range collapsed at (paras[1].firstChild, 1) -FAIL paras[1].firstChild.textContent = paras[1].firstChild.textContent, with unselected range collapsed at (paras[1].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[1].firstChild.textContent = paras[1].firstChild.textContent, with selected range collapsed at (paras[1].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[1].firstChild.textContent += "", with unselected range collapsed at (paras[1].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[1].firstChild.textContent += "", with selected range collapsed at (paras[1].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS paras[1].firstChild.textContent = paras[1].firstChild.textContent, with unselected range collapsed at (paras[1].firstChild, 1) +PASS paras[1].firstChild.textContent = paras[1].firstChild.textContent, with selected range collapsed at (paras[1].firstChild, 1) +PASS paras[1].firstChild.textContent += "", with unselected range collapsed at (paras[1].firstChild, 1) +PASS paras[1].firstChild.textContent += "", with selected range collapsed at (paras[1].firstChild, 1) PASS paras[1].firstChild.textContent += "foo", with unselected range collapsed at (paras[1].firstChild, 1) PASS paras[1].firstChild.textContent += "foo", with selected range collapsed at (paras[1].firstChild, 1) PASS paras[1].firstChild.textContent += paras[1].firstChild.textContent, with unselected range collapsed at (paras[1].firstChild, 1) @@ -531,10 +531,10 @@ PASS paras[1].firstChild.nodeValue = "", with selected range collapsed at (paras[1].firstChild, 1) PASS paras[1].firstChild.nodeValue = "foo", with unselected range collapsed at (paras[1].firstChild, 1) PASS paras[1].firstChild.nodeValue = "foo", with selected range collapsed at (paras[1].firstChild, 1) -FAIL paras[1].firstChild.nodeValue = paras[1].firstChild.nodeValue, with unselected range collapsed at (paras[1].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[1].firstChild.nodeValue = paras[1].firstChild.nodeValue, with selected range collapsed at (paras[1].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[1].firstChild.nodeValue += "", with unselected range collapsed at (paras[1].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[1].firstChild.nodeValue += "", with selected range collapsed at (paras[1].firstChild, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS paras[1].firstChild.nodeValue = paras[1].firstChild.nodeValue, with unselected range collapsed at (paras[1].firstChild, 1) +PASS paras[1].firstChild.nodeValue = paras[1].firstChild.nodeValue, with selected range collapsed at (paras[1].firstChild, 1) +PASS paras[1].firstChild.nodeValue += "", with unselected range collapsed at (paras[1].firstChild, 1) +PASS paras[1].firstChild.nodeValue += "", with selected range collapsed at (paras[1].firstChild, 1) PASS paras[1].firstChild.nodeValue += "foo", with unselected range collapsed at (paras[1].firstChild, 1) PASS paras[1].firstChild.nodeValue += "foo", with selected range collapsed at (paras[1].firstChild, 1) PASS paras[1].firstChild.nodeValue += paras[1].firstChild.nodeValue, with unselected range collapsed at (paras[1].firstChild, 1) @@ -543,10 +543,10 @@ PASS paras[1].firstChild.data = "", with selected range on paras[1].firstChild from 0 to paras[1].firstChild.length PASS paras[1].firstChild.data = "foo", with unselected range on paras[1].firstChild from 0 to paras[1].firstChild.length PASS paras[1].firstChild.data = "foo", with selected range on paras[1].firstChild from 0 to paras[1].firstChild.length -FAIL paras[1].firstChild.data = paras[1].firstChild.data, with unselected range on paras[1].firstChild from 0 to paras[1].firstChild.length assert_equals: Wrong end offset expected 0 but got 9 -FAIL paras[1].firstChild.data = paras[1].firstChild.data, with selected range on paras[1].firstChild from 0 to paras[1].firstChild.length assert_equals: Wrong end offset expected 0 but got 9 -FAIL paras[1].firstChild.data += "", with unselected range on paras[1].firstChild from 0 to paras[1].firstChild.length assert_equals: Wrong end offset expected 0 but got 9 -FAIL paras[1].firstChild.data += "", with selected range on paras[1].firstChild from 0 to paras[1].firstChild.length assert_equals: Wrong end offset expected 0 but got 9 +PASS paras[1].firstChild.data = paras[1].firstChild.data, with unselected range on paras[1].firstChild from 0 to paras[1].firstChild.length +PASS paras[1].firstChild.data = paras[1].firstChild.data, with selected range on paras[1].firstChild from 0 to paras[1].firstChild.length +PASS paras[1].firstChild.data += "", with unselected range on paras[1].firstChild from 0 to paras[1].firstChild.length +PASS paras[1].firstChild.data += "", with selected range on paras[1].firstChild from 0 to paras[1].firstChild.length PASS paras[1].firstChild.data += "foo", with unselected range on paras[1].firstChild from 0 to paras[1].firstChild.length PASS paras[1].firstChild.data += "foo", with selected range on paras[1].firstChild from 0 to paras[1].firstChild.length PASS paras[1].firstChild.data += paras[1].firstChild.data, with unselected range on paras[1].firstChild from 0 to paras[1].firstChild.length @@ -555,10 +555,10 @@ PASS paras[1].firstChild.textContent = "", with selected range on paras[1].firstChild from 0 to paras[1].firstChild.length PASS paras[1].firstChild.textContent = "foo", with unselected range on paras[1].firstChild from 0 to paras[1].firstChild.length PASS paras[1].firstChild.textContent = "foo", with selected range on paras[1].firstChild from 0 to paras[1].firstChild.length -FAIL paras[1].firstChild.textContent = paras[1].firstChild.textContent, with unselected range on paras[1].firstChild from 0 to paras[1].firstChild.length assert_equals: Wrong end offset expected 0 but got 9 -FAIL paras[1].firstChild.textContent = paras[1].firstChild.textContent, with selected range on paras[1].firstChild from 0 to paras[1].firstChild.length assert_equals: Wrong end offset expected 0 but got 9 -FAIL paras[1].firstChild.textContent += "", with unselected range on paras[1].firstChild from 0 to paras[1].firstChild.length assert_equals: Wrong end offset expected 0 but got 9 -FAIL paras[1].firstChild.textContent += "", with selected range on paras[1].firstChild from 0 to paras[1].firstChild.length assert_equals: Wrong end offset expected 0 but got 9 +PASS paras[1].firstChild.textContent = paras[1].firstChild.textContent, with unselected range on paras[1].firstChild from 0 to paras[1].firstChild.length +PASS paras[1].firstChild.textContent = paras[1].firstChild.textContent, with selected range on paras[1].firstChild from 0 to paras[1].firstChild.length +PASS paras[1].firstChild.textContent += "", with unselected range on paras[1].firstChild from 0 to paras[1].firstChild.length +PASS paras[1].firstChild.textContent += "", with selected range on paras[1].firstChild from 0 to paras[1].firstChild.length PASS paras[1].firstChild.textContent += "foo", with unselected range on paras[1].firstChild from 0 to paras[1].firstChild.length PASS paras[1].firstChild.textContent += "foo", with selected range on paras[1].firstChild from 0 to paras[1].firstChild.length PASS paras[1].firstChild.textContent += paras[1].firstChild.textContent, with unselected range on paras[1].firstChild from 0 to paras[1].firstChild.length @@ -567,10 +567,10 @@ PASS paras[1].firstChild.nodeValue = "", with selected range on paras[1].firstChild from 0 to paras[1].firstChild.length PASS paras[1].firstChild.nodeValue = "foo", with unselected range on paras[1].firstChild from 0 to paras[1].firstChild.length PASS paras[1].firstChild.nodeValue = "foo", with selected range on paras[1].firstChild from 0 to paras[1].firstChild.length -FAIL paras[1].firstChild.nodeValue = paras[1].firstChild.nodeValue, with unselected range on paras[1].firstChild from 0 to paras[1].firstChild.length assert_equals: Wrong end offset expected 0 but got 9 -FAIL paras[1].firstChild.nodeValue = paras[1].firstChild.nodeValue, with selected range on paras[1].firstChild from 0 to paras[1].firstChild.length assert_equals: Wrong end offset expected 0 but got 9 -FAIL paras[1].firstChild.nodeValue += "", with unselected range on paras[1].firstChild from 0 to paras[1].firstChild.length assert_equals: Wrong end offset expected 0 but got 9 -FAIL paras[1].firstChild.nodeValue += "", with selected range on paras[1].firstChild from 0 to paras[1].firstChild.length assert_equals: Wrong end offset expected 0 but got 9 +PASS paras[1].firstChild.nodeValue = paras[1].firstChild.nodeValue, with unselected range on paras[1].firstChild from 0 to paras[1].firstChild.length +PASS paras[1].firstChild.nodeValue = paras[1].firstChild.nodeValue, with selected range on paras[1].firstChild from 0 to paras[1].firstChild.length +PASS paras[1].firstChild.nodeValue += "", with unselected range on paras[1].firstChild from 0 to paras[1].firstChild.length +PASS paras[1].firstChild.nodeValue += "", with selected range on paras[1].firstChild from 0 to paras[1].firstChild.length PASS paras[1].firstChild.nodeValue += "foo", with unselected range on paras[1].firstChild from 0 to paras[1].firstChild.length PASS paras[1].firstChild.nodeValue += "foo", with selected range on paras[1].firstChild from 0 to paras[1].firstChild.length PASS paras[1].firstChild.nodeValue += paras[1].firstChild.nodeValue, with unselected range on paras[1].firstChild from 0 to paras[1].firstChild.length @@ -579,10 +579,10 @@ PASS paras[1].firstChild.data = "", with selected range on paras[1].firstChild from 1 to paras[1].firstChild.length PASS paras[1].firstChild.data = "foo", with unselected range on paras[1].firstChild from 1 to paras[1].firstChild.length PASS paras[1].firstChild.data = "foo", with selected range on paras[1].firstChild from 1 to paras[1].firstChild.length -FAIL paras[1].firstChild.data = paras[1].firstChild.data, with unselected range on paras[1].firstChild from 1 to paras[1].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[1].firstChild.data = paras[1].firstChild.data, with selected range on paras[1].firstChild from 1 to paras[1].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[1].firstChild.data += "", with unselected range on paras[1].firstChild from 1 to paras[1].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[1].firstChild.data += "", with selected range on paras[1].firstChild from 1 to paras[1].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 +PASS paras[1].firstChild.data = paras[1].firstChild.data, with unselected range on paras[1].firstChild from 1 to paras[1].firstChild.length +PASS paras[1].firstChild.data = paras[1].firstChild.data, with selected range on paras[1].firstChild from 1 to paras[1].firstChild.length +PASS paras[1].firstChild.data += "", with unselected range on paras[1].firstChild from 1 to paras[1].firstChild.length +PASS paras[1].firstChild.data += "", with selected range on paras[1].firstChild from 1 to paras[1].firstChild.length PASS paras[1].firstChild.data += "foo", with unselected range on paras[1].firstChild from 1 to paras[1].firstChild.length PASS paras[1].firstChild.data += "foo", with selected range on paras[1].firstChild from 1 to paras[1].firstChild.length PASS paras[1].firstChild.data += paras[1].firstChild.data, with unselected range on paras[1].firstChild from 1 to paras[1].firstChild.length @@ -591,10 +591,10 @@ PASS paras[1].firstChild.textContent = "", with selected range on paras[1].firstChild from 1 to paras[1].firstChild.length PASS paras[1].firstChild.textContent = "foo", with unselected range on paras[1].firstChild from 1 to paras[1].firstChild.length PASS paras[1].firstChild.textContent = "foo", with selected range on paras[1].firstChild from 1 to paras[1].firstChild.length -FAIL paras[1].firstChild.textContent = paras[1].firstChild.textContent, with unselected range on paras[1].firstChild from 1 to paras[1].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[1].firstChild.textContent = paras[1].firstChild.textContent, with selected range on paras[1].firstChild from 1 to paras[1].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[1].firstChild.textContent += "", with unselected range on paras[1].firstChild from 1 to paras[1].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[1].firstChild.textContent += "", with selected range on paras[1].firstChild from 1 to paras[1].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 +PASS paras[1].firstChild.textContent = paras[1].firstChild.textContent, with unselected range on paras[1].firstChild from 1 to paras[1].firstChild.length +PASS paras[1].firstChild.textContent = paras[1].firstChild.textContent, with selected range on paras[1].firstChild from 1 to paras[1].firstChild.length +PASS paras[1].firstChild.textContent += "", with unselected range on paras[1].firstChild from 1 to paras[1].firstChild.length +PASS paras[1].firstChild.textContent += "", with selected range on paras[1].firstChild from 1 to paras[1].firstChild.length PASS paras[1].firstChild.textContent += "foo", with unselected range on paras[1].firstChild from 1 to paras[1].firstChild.length PASS paras[1].firstChild.textContent += "foo", with selected range on paras[1].firstChild from 1 to paras[1].firstChild.length PASS paras[1].firstChild.textContent += paras[1].firstChild.textContent, with unselected range on paras[1].firstChild from 1 to paras[1].firstChild.length @@ -603,10 +603,10 @@ PASS paras[1].firstChild.nodeValue = "", with selected range on paras[1].firstChild from 1 to paras[1].firstChild.length PASS paras[1].firstChild.nodeValue = "foo", with unselected range on paras[1].firstChild from 1 to paras[1].firstChild.length PASS paras[1].firstChild.nodeValue = "foo", with selected range on paras[1].firstChild from 1 to paras[1].firstChild.length -FAIL paras[1].firstChild.nodeValue = paras[1].firstChild.nodeValue, with unselected range on paras[1].firstChild from 1 to paras[1].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[1].firstChild.nodeValue = paras[1].firstChild.nodeValue, with selected range on paras[1].firstChild from 1 to paras[1].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[1].firstChild.nodeValue += "", with unselected range on paras[1].firstChild from 1 to paras[1].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 -FAIL paras[1].firstChild.nodeValue += "", with selected range on paras[1].firstChild from 1 to paras[1].firstChild.length assert_equals: Wrong start offset expected 0 but got 1 +PASS paras[1].firstChild.nodeValue = paras[1].firstChild.nodeValue, with unselected range on paras[1].firstChild from 1 to paras[1].firstChild.length +PASS paras[1].firstChild.nodeValue = paras[1].firstChild.nodeValue, with selected range on paras[1].firstChild from 1 to paras[1].firstChild.length +PASS paras[1].firstChild.nodeValue += "", with unselected range on paras[1].firstChild from 1 to paras[1].firstChild.length +PASS paras[1].firstChild.nodeValue += "", with selected range on paras[1].firstChild from 1 to paras[1].firstChild.length PASS paras[1].firstChild.nodeValue += "foo", with unselected range on paras[1].firstChild from 1 to paras[1].firstChild.length PASS paras[1].firstChild.nodeValue += "foo", with selected range on paras[1].firstChild from 1 to paras[1].firstChild.length PASS paras[1].firstChild.nodeValue += paras[1].firstChild.nodeValue, with unselected range on paras[1].firstChild from 1 to paras[1].firstChild.length @@ -615,10 +615,10 @@ PASS paras[1].firstChild.data = "", with selected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) PASS paras[1].firstChild.data = "foo", with unselected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) PASS paras[1].firstChild.data = "foo", with selected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) -FAIL paras[1].firstChild.data = paras[1].firstChild.data, with unselected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) assert_equals: Wrong start offset expected 0 but got 9 -FAIL paras[1].firstChild.data = paras[1].firstChild.data, with selected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) assert_equals: Wrong start offset expected 0 but got 9 -FAIL paras[1].firstChild.data += "", with unselected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) assert_equals: Wrong start offset expected 0 but got 9 -FAIL paras[1].firstChild.data += "", with selected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) assert_equals: Wrong start offset expected 0 but got 9 +PASS paras[1].firstChild.data = paras[1].firstChild.data, with unselected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) +PASS paras[1].firstChild.data = paras[1].firstChild.data, with selected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) +PASS paras[1].firstChild.data += "", with unselected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) +PASS paras[1].firstChild.data += "", with selected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) PASS paras[1].firstChild.data += "foo", with unselected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) PASS paras[1].firstChild.data += "foo", with selected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) PASS paras[1].firstChild.data += paras[1].firstChild.data, with unselected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) @@ -627,10 +627,10 @@ PASS paras[1].firstChild.textContent = "", with selected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) PASS paras[1].firstChild.textContent = "foo", with unselected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) PASS paras[1].firstChild.textContent = "foo", with selected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) -FAIL paras[1].firstChild.textContent = paras[1].firstChild.textContent, with unselected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) assert_equals: Wrong start offset expected 0 but got 9 -FAIL paras[1].firstChild.textContent = paras[1].firstChild.textContent, with selected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) assert_equals: Wrong start offset expected 0 but got 9 -FAIL paras[1].firstChild.textContent += "", with unselected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) assert_equals: Wrong start offset expected 0 but got 9 -FAIL paras[1].firstChild.textContent += "", with selected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) assert_equals: Wrong start offset expected 0 but got 9 +PASS paras[1].firstChild.textContent = paras[1].firstChild.textContent, with unselected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) +PASS paras[1].firstChild.textContent = paras[1].firstChild.textContent, with selected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) +PASS paras[1].firstChild.textContent += "", with unselected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) +PASS paras[1].firstChild.textContent += "", with selected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) PASS paras[1].firstChild.textContent += "foo", with unselected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) PASS paras[1].firstChild.textContent += "foo", with selected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) PASS paras[1].firstChild.textContent += paras[1].firstChild.textContent, with unselected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) @@ -639,10 +639,10 @@ PASS paras[1].firstChild.nodeValue = "", with selected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) PASS paras[1].firstChild.nodeValue = "foo", with unselected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) PASS paras[1].firstChild.nodeValue = "foo", with selected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) -FAIL paras[1].firstChild.nodeValue = paras[1].firstChild.nodeValue, with unselected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) assert_equals: Wrong start offset expected 0 but got 9 -FAIL paras[1].firstChild.nodeValue = paras[1].firstChild.nodeValue, with selected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) assert_equals: Wrong start offset expected 0 but got 9 -FAIL paras[1].firstChild.nodeValue += "", with unselected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) assert_equals: Wrong start offset expected 0 but got 9 -FAIL paras[1].firstChild.nodeValue += "", with selected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) assert_equals: Wrong start offset expected 0 but got 9 +PASS paras[1].firstChild.nodeValue = paras[1].firstChild.nodeValue, with unselected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) +PASS paras[1].firstChild.nodeValue = paras[1].firstChild.nodeValue, with selected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) +PASS paras[1].firstChild.nodeValue += "", with unselected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) +PASS paras[1].firstChild.nodeValue += "", with selected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) PASS paras[1].firstChild.nodeValue += "foo", with unselected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) PASS paras[1].firstChild.nodeValue += "foo", with selected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) PASS paras[1].firstChild.nodeValue += paras[1].firstChild.nodeValue, with unselected range collapsed at (paras[1].firstChild, paras[1].firstChild.length) @@ -687,9 +687,9 @@ PASS foreignTextNode.data = "", with selected range on foreignTextNode from 0 to 1 PASS foreignTextNode.data = "foo", with unselected range on foreignTextNode from 0 to 1 PASS foreignTextNode.data = "foo", with selected range on foreignTextNode from 0 to 1 -FAIL foreignTextNode.data = foreignTextNode.data, with unselected range on foreignTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS foreignTextNode.data = foreignTextNode.data, with unselected range on foreignTextNode from 0 to 1 PASS foreignTextNode.data = foreignTextNode.data, with selected range on foreignTextNode from 0 to 1 -FAIL foreignTextNode.data += "", with unselected range on foreignTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS foreignTextNode.data += "", with unselected range on foreignTextNode from 0 to 1 PASS foreignTextNode.data += "", with selected range on foreignTextNode from 0 to 1 PASS foreignTextNode.data += "foo", with unselected range on foreignTextNode from 0 to 1 PASS foreignTextNode.data += "foo", with selected range on foreignTextNode from 0 to 1 @@ -699,9 +699,9 @@ PASS foreignTextNode.textContent = "", with selected range on foreignTextNode from 0 to 1 PASS foreignTextNode.textContent = "foo", with unselected range on foreignTextNode from 0 to 1 PASS foreignTextNode.textContent = "foo", with selected range on foreignTextNode from 0 to 1 -FAIL foreignTextNode.textContent = foreignTextNode.textContent, with unselected range on foreignTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS foreignTextNode.textContent = foreignTextNode.textContent, with unselected range on foreignTextNode from 0 to 1 PASS foreignTextNode.textContent = foreignTextNode.textContent, with selected range on foreignTextNode from 0 to 1 -FAIL foreignTextNode.textContent += "", with unselected range on foreignTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS foreignTextNode.textContent += "", with unselected range on foreignTextNode from 0 to 1 PASS foreignTextNode.textContent += "", with selected range on foreignTextNode from 0 to 1 PASS foreignTextNode.textContent += "foo", with unselected range on foreignTextNode from 0 to 1 PASS foreignTextNode.textContent += "foo", with selected range on foreignTextNode from 0 to 1 @@ -711,9 +711,9 @@ PASS foreignTextNode.nodeValue = "", with selected range on foreignTextNode from 0 to 1 PASS foreignTextNode.nodeValue = "foo", with unselected range on foreignTextNode from 0 to 1 PASS foreignTextNode.nodeValue = "foo", with selected range on foreignTextNode from 0 to 1 -FAIL foreignTextNode.nodeValue = foreignTextNode.nodeValue, with unselected range on foreignTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS foreignTextNode.nodeValue = foreignTextNode.nodeValue, with unselected range on foreignTextNode from 0 to 1 PASS foreignTextNode.nodeValue = foreignTextNode.nodeValue, with selected range on foreignTextNode from 0 to 1 -FAIL foreignTextNode.nodeValue += "", with unselected range on foreignTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS foreignTextNode.nodeValue += "", with unselected range on foreignTextNode from 0 to 1 PASS foreignTextNode.nodeValue += "", with selected range on foreignTextNode from 0 to 1 PASS foreignTextNode.nodeValue += "foo", with unselected range on foreignTextNode from 0 to 1 PASS foreignTextNode.nodeValue += "foo", with selected range on foreignTextNode from 0 to 1 @@ -723,9 +723,9 @@ PASS foreignTextNode.data = "", with selected range collapsed at (foreignTextNode, 1) PASS foreignTextNode.data = "foo", with unselected range collapsed at (foreignTextNode, 1) PASS foreignTextNode.data = "foo", with selected range collapsed at (foreignTextNode, 1) -FAIL foreignTextNode.data = foreignTextNode.data, with unselected range collapsed at (foreignTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignTextNode.data = foreignTextNode.data, with unselected range collapsed at (foreignTextNode, 1) PASS foreignTextNode.data = foreignTextNode.data, with selected range collapsed at (foreignTextNode, 1) -FAIL foreignTextNode.data += "", with unselected range collapsed at (foreignTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignTextNode.data += "", with unselected range collapsed at (foreignTextNode, 1) PASS foreignTextNode.data += "", with selected range collapsed at (foreignTextNode, 1) PASS foreignTextNode.data += "foo", with unselected range collapsed at (foreignTextNode, 1) PASS foreignTextNode.data += "foo", with selected range collapsed at (foreignTextNode, 1) @@ -735,9 +735,9 @@ PASS foreignTextNode.textContent = "", with selected range collapsed at (foreignTextNode, 1) PASS foreignTextNode.textContent = "foo", with unselected range collapsed at (foreignTextNode, 1) PASS foreignTextNode.textContent = "foo", with selected range collapsed at (foreignTextNode, 1) -FAIL foreignTextNode.textContent = foreignTextNode.textContent, with unselected range collapsed at (foreignTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignTextNode.textContent = foreignTextNode.textContent, with unselected range collapsed at (foreignTextNode, 1) PASS foreignTextNode.textContent = foreignTextNode.textContent, with selected range collapsed at (foreignTextNode, 1) -FAIL foreignTextNode.textContent += "", with unselected range collapsed at (foreignTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignTextNode.textContent += "", with unselected range collapsed at (foreignTextNode, 1) PASS foreignTextNode.textContent += "", with selected range collapsed at (foreignTextNode, 1) PASS foreignTextNode.textContent += "foo", with unselected range collapsed at (foreignTextNode, 1) PASS foreignTextNode.textContent += "foo", with selected range collapsed at (foreignTextNode, 1) @@ -747,9 +747,9 @@ PASS foreignTextNode.nodeValue = "", with selected range collapsed at (foreignTextNode, 1) PASS foreignTextNode.nodeValue = "foo", with unselected range collapsed at (foreignTextNode, 1) PASS foreignTextNode.nodeValue = "foo", with selected range collapsed at (foreignTextNode, 1) -FAIL foreignTextNode.nodeValue = foreignTextNode.nodeValue, with unselected range collapsed at (foreignTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignTextNode.nodeValue = foreignTextNode.nodeValue, with unselected range collapsed at (foreignTextNode, 1) PASS foreignTextNode.nodeValue = foreignTextNode.nodeValue, with selected range collapsed at (foreignTextNode, 1) -FAIL foreignTextNode.nodeValue += "", with unselected range collapsed at (foreignTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignTextNode.nodeValue += "", with unselected range collapsed at (foreignTextNode, 1) PASS foreignTextNode.nodeValue += "", with selected range collapsed at (foreignTextNode, 1) PASS foreignTextNode.nodeValue += "foo", with unselected range collapsed at (foreignTextNode, 1) PASS foreignTextNode.nodeValue += "foo", with selected range collapsed at (foreignTextNode, 1) @@ -759,9 +759,9 @@ PASS foreignTextNode.data = "", with selected range on foreignTextNode from 0 to foreignTextNode.length PASS foreignTextNode.data = "foo", with unselected range on foreignTextNode from 0 to foreignTextNode.length PASS foreignTextNode.data = "foo", with selected range on foreignTextNode from 0 to foreignTextNode.length -FAIL foreignTextNode.data = foreignTextNode.data, with unselected range on foreignTextNode from 0 to foreignTextNode.length assert_equals: Wrong end offset expected 0 but got 112 +PASS foreignTextNode.data = foreignTextNode.data, with unselected range on foreignTextNode from 0 to foreignTextNode.length PASS foreignTextNode.data = foreignTextNode.data, with selected range on foreignTextNode from 0 to foreignTextNode.length -FAIL foreignTextNode.data += "", with unselected range on foreignTextNode from 0 to foreignTextNode.length assert_equals: Wrong end offset expected 0 but got 112 +PASS foreignTextNode.data += "", with unselected range on foreignTextNode from 0 to foreignTextNode.length PASS foreignTextNode.data += "", with selected range on foreignTextNode from 0 to foreignTextNode.length PASS foreignTextNode.data += "foo", with unselected range on foreignTextNode from 0 to foreignTextNode.length PASS foreignTextNode.data += "foo", with selected range on foreignTextNode from 0 to foreignTextNode.length @@ -771,9 +771,9 @@ PASS foreignTextNode.textContent = "", with selected range on foreignTextNode from 0 to foreignTextNode.length PASS foreignTextNode.textContent = "foo", with unselected range on foreignTextNode from 0 to foreignTextNode.length PASS foreignTextNode.textContent = "foo", with selected range on foreignTextNode from 0 to foreignTextNode.length -FAIL foreignTextNode.textContent = foreignTextNode.textContent, with unselected range on foreignTextNode from 0 to foreignTextNode.length assert_equals: Wrong end offset expected 0 but got 112 +PASS foreignTextNode.textContent = foreignTextNode.textContent, with unselected range on foreignTextNode from 0 to foreignTextNode.length PASS foreignTextNode.textContent = foreignTextNode.textContent, with selected range on foreignTextNode from 0 to foreignTextNode.length -FAIL foreignTextNode.textContent += "", with unselected range on foreignTextNode from 0 to foreignTextNode.length assert_equals: Wrong end offset expected 0 but got 112 +PASS foreignTextNode.textContent += "", with unselected range on foreignTextNode from 0 to foreignTextNode.length PASS foreignTextNode.textContent += "", with selected range on foreignTextNode from 0 to foreignTextNode.length PASS foreignTextNode.textContent += "foo", with unselected range on foreignTextNode from 0 to foreignTextNode.length PASS foreignTextNode.textContent += "foo", with selected range on foreignTextNode from 0 to foreignTextNode.length @@ -783,9 +783,9 @@ PASS foreignTextNode.nodeValue = "", with selected range on foreignTextNode from 0 to foreignTextNode.length PASS foreignTextNode.nodeValue = "foo", with unselected range on foreignTextNode from 0 to foreignTextNode.length PASS foreignTextNode.nodeValue = "foo", with selected range on foreignTextNode from 0 to foreignTextNode.length -FAIL foreignTextNode.nodeValue = foreignTextNode.nodeValue, with unselected range on foreignTextNode from 0 to foreignTextNode.length assert_equals: Wrong end offset expected 0 but got 112 +PASS foreignTextNode.nodeValue = foreignTextNode.nodeValue, with unselected range on foreignTextNode from 0 to foreignTextNode.length PASS foreignTextNode.nodeValue = foreignTextNode.nodeValue, with selected range on foreignTextNode from 0 to foreignTextNode.length -FAIL foreignTextNode.nodeValue += "", with unselected range on foreignTextNode from 0 to foreignTextNode.length assert_equals: Wrong end offset expected 0 but got 112 +PASS foreignTextNode.nodeValue += "", with unselected range on foreignTextNode from 0 to foreignTextNode.length PASS foreignTextNode.nodeValue += "", with selected range on foreignTextNode from 0 to foreignTextNode.length PASS foreignTextNode.nodeValue += "foo", with unselected range on foreignTextNode from 0 to foreignTextNode.length PASS foreignTextNode.nodeValue += "foo", with selected range on foreignTextNode from 0 to foreignTextNode.length @@ -795,9 +795,9 @@ PASS foreignTextNode.data = "", with selected range on foreignTextNode from 1 to foreignTextNode.length PASS foreignTextNode.data = "foo", with unselected range on foreignTextNode from 1 to foreignTextNode.length PASS foreignTextNode.data = "foo", with selected range on foreignTextNode from 1 to foreignTextNode.length -FAIL foreignTextNode.data = foreignTextNode.data, with unselected range on foreignTextNode from 1 to foreignTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignTextNode.data = foreignTextNode.data, with unselected range on foreignTextNode from 1 to foreignTextNode.length PASS foreignTextNode.data = foreignTextNode.data, with selected range on foreignTextNode from 1 to foreignTextNode.length -FAIL foreignTextNode.data += "", with unselected range on foreignTextNode from 1 to foreignTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignTextNode.data += "", with unselected range on foreignTextNode from 1 to foreignTextNode.length PASS foreignTextNode.data += "", with selected range on foreignTextNode from 1 to foreignTextNode.length PASS foreignTextNode.data += "foo", with unselected range on foreignTextNode from 1 to foreignTextNode.length PASS foreignTextNode.data += "foo", with selected range on foreignTextNode from 1 to foreignTextNode.length @@ -807,9 +807,9 @@ PASS foreignTextNode.textContent = "", with selected range on foreignTextNode from 1 to foreignTextNode.length PASS foreignTextNode.textContent = "foo", with unselected range on foreignTextNode from 1 to foreignTextNode.length PASS foreignTextNode.textContent = "foo", with selected range on foreignTextNode from 1 to foreignTextNode.length -FAIL foreignTextNode.textContent = foreignTextNode.textContent, with unselected range on foreignTextNode from 1 to foreignTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignTextNode.textContent = foreignTextNode.textContent, with unselected range on foreignTextNode from 1 to foreignTextNode.length PASS foreignTextNode.textContent = foreignTextNode.textContent, with selected range on foreignTextNode from 1 to foreignTextNode.length -FAIL foreignTextNode.textContent += "", with unselected range on foreignTextNode from 1 to foreignTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignTextNode.textContent += "", with unselected range on foreignTextNode from 1 to foreignTextNode.length PASS foreignTextNode.textContent += "", with selected range on foreignTextNode from 1 to foreignTextNode.length PASS foreignTextNode.textContent += "foo", with unselected range on foreignTextNode from 1 to foreignTextNode.length PASS foreignTextNode.textContent += "foo", with selected range on foreignTextNode from 1 to foreignTextNode.length @@ -819,9 +819,9 @@ PASS foreignTextNode.nodeValue = "", with selected range on foreignTextNode from 1 to foreignTextNode.length PASS foreignTextNode.nodeValue = "foo", with unselected range on foreignTextNode from 1 to foreignTextNode.length PASS foreignTextNode.nodeValue = "foo", with selected range on foreignTextNode from 1 to foreignTextNode.length -FAIL foreignTextNode.nodeValue = foreignTextNode.nodeValue, with unselected range on foreignTextNode from 1 to foreignTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignTextNode.nodeValue = foreignTextNode.nodeValue, with unselected range on foreignTextNode from 1 to foreignTextNode.length PASS foreignTextNode.nodeValue = foreignTextNode.nodeValue, with selected range on foreignTextNode from 1 to foreignTextNode.length -FAIL foreignTextNode.nodeValue += "", with unselected range on foreignTextNode from 1 to foreignTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignTextNode.nodeValue += "", with unselected range on foreignTextNode from 1 to foreignTextNode.length PASS foreignTextNode.nodeValue += "", with selected range on foreignTextNode from 1 to foreignTextNode.length PASS foreignTextNode.nodeValue += "foo", with unselected range on foreignTextNode from 1 to foreignTextNode.length PASS foreignTextNode.nodeValue += "foo", with selected range on foreignTextNode from 1 to foreignTextNode.length @@ -831,9 +831,9 @@ PASS foreignTextNode.data = "", with selected range collapsed at (foreignTextNode, foreignTextNode.length) PASS foreignTextNode.data = "foo", with unselected range collapsed at (foreignTextNode, foreignTextNode.length) PASS foreignTextNode.data = "foo", with selected range collapsed at (foreignTextNode, foreignTextNode.length) -FAIL foreignTextNode.data = foreignTextNode.data, with unselected range collapsed at (foreignTextNode, foreignTextNode.length) assert_equals: Wrong start offset expected 0 but got 112 +PASS foreignTextNode.data = foreignTextNode.data, with unselected range collapsed at (foreignTextNode, foreignTextNode.length) PASS foreignTextNode.data = foreignTextNode.data, with selected range collapsed at (foreignTextNode, foreignTextNode.length) -FAIL foreignTextNode.data += "", with unselected range collapsed at (foreignTextNode, foreignTextNode.length) assert_equals: Wrong start offset expected 0 but got 112 +PASS foreignTextNode.data += "", with unselected range collapsed at (foreignTextNode, foreignTextNode.length) PASS foreignTextNode.data += "", with selected range collapsed at (foreignTextNode, foreignTextNode.length) PASS foreignTextNode.data += "foo", with unselected range collapsed at (foreignTextNode, foreignTextNode.length) PASS foreignTextNode.data += "foo", with selected range collapsed at (foreignTextNode, foreignTextNode.length) @@ -843,9 +843,9 @@ PASS foreignTextNode.textContent = "", with selected range collapsed at (foreignTextNode, foreignTextNode.length) PASS foreignTextNode.textContent = "foo", with unselected range collapsed at (foreignTextNode, foreignTextNode.length) PASS foreignTextNode.textContent = "foo", with selected range collapsed at (foreignTextNode, foreignTextNode.length) -FAIL foreignTextNode.textContent = foreignTextNode.textContent, with unselected range collapsed at (foreignTextNode, foreignTextNode.length) assert_equals: Wrong start offset expected 0 but got 112 +PASS foreignTextNode.textContent = foreignTextNode.textContent, with unselected range collapsed at (foreignTextNode, foreignTextNode.length) PASS foreignTextNode.textContent = foreignTextNode.textContent, with selected range collapsed at (foreignTextNode, foreignTextNode.length) -FAIL foreignTextNode.textContent += "", with unselected range collapsed at (foreignTextNode, foreignTextNode.length) assert_equals: Wrong start offset expected 0 but got 112 +PASS foreignTextNode.textContent += "", with unselected range collapsed at (foreignTextNode, foreignTextNode.length) PASS foreignTextNode.textContent += "", with selected range collapsed at (foreignTextNode, foreignTextNode.length) PASS foreignTextNode.textContent += "foo", with unselected range collapsed at (foreignTextNode, foreignTextNode.length) PASS foreignTextNode.textContent += "foo", with selected range collapsed at (foreignTextNode, foreignTextNode.length) @@ -855,9 +855,9 @@ PASS foreignTextNode.nodeValue = "", with selected range collapsed at (foreignTextNode, foreignTextNode.length) PASS foreignTextNode.nodeValue = "foo", with unselected range collapsed at (foreignTextNode, foreignTextNode.length) PASS foreignTextNode.nodeValue = "foo", with selected range collapsed at (foreignTextNode, foreignTextNode.length) -FAIL foreignTextNode.nodeValue = foreignTextNode.nodeValue, with unselected range collapsed at (foreignTextNode, foreignTextNode.length) assert_equals: Wrong start offset expected 0 but got 112 +PASS foreignTextNode.nodeValue = foreignTextNode.nodeValue, with unselected range collapsed at (foreignTextNode, foreignTextNode.length) PASS foreignTextNode.nodeValue = foreignTextNode.nodeValue, with selected range collapsed at (foreignTextNode, foreignTextNode.length) -FAIL foreignTextNode.nodeValue += "", with unselected range collapsed at (foreignTextNode, foreignTextNode.length) assert_equals: Wrong start offset expected 0 but got 112 +PASS foreignTextNode.nodeValue += "", with unselected range collapsed at (foreignTextNode, foreignTextNode.length) PASS foreignTextNode.nodeValue += "", with selected range collapsed at (foreignTextNode, foreignTextNode.length) PASS foreignTextNode.nodeValue += "foo", with unselected range collapsed at (foreignTextNode, foreignTextNode.length) PASS foreignTextNode.nodeValue += "foo", with selected range collapsed at (foreignTextNode, foreignTextNode.length) @@ -903,9 +903,9 @@ PASS xmlTextNode.data = "", with selected range on xmlTextNode from 0 to 1 PASS xmlTextNode.data = "foo", with unselected range on xmlTextNode from 0 to 1 PASS xmlTextNode.data = "foo", with selected range on xmlTextNode from 0 to 1 -FAIL xmlTextNode.data = xmlTextNode.data, with unselected range on xmlTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS xmlTextNode.data = xmlTextNode.data, with unselected range on xmlTextNode from 0 to 1 PASS xmlTextNode.data = xmlTextNode.data, with selected range on xmlTextNode from 0 to 1 -FAIL xmlTextNode.data += "", with unselected range on xmlTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS xmlTextNode.data += "", with unselected range on xmlTextNode from 0 to 1 PASS xmlTextNode.data += "", with selected range on xmlTextNode from 0 to 1 PASS xmlTextNode.data += "foo", with unselected range on xmlTextNode from 0 to 1 PASS xmlTextNode.data += "foo", with selected range on xmlTextNode from 0 to 1 @@ -915,9 +915,9 @@ PASS xmlTextNode.textContent = "", with selected range on xmlTextNode from 0 to 1 PASS xmlTextNode.textContent = "foo", with unselected range on xmlTextNode from 0 to 1 PASS xmlTextNode.textContent = "foo", with selected range on xmlTextNode from 0 to 1 -FAIL xmlTextNode.textContent = xmlTextNode.textContent, with unselected range on xmlTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS xmlTextNode.textContent = xmlTextNode.textContent, with unselected range on xmlTextNode from 0 to 1 PASS xmlTextNode.textContent = xmlTextNode.textContent, with selected range on xmlTextNode from 0 to 1 -FAIL xmlTextNode.textContent += "", with unselected range on xmlTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS xmlTextNode.textContent += "", with unselected range on xmlTextNode from 0 to 1 PASS xmlTextNode.textContent += "", with selected range on xmlTextNode from 0 to 1 PASS xmlTextNode.textContent += "foo", with unselected range on xmlTextNode from 0 to 1 PASS xmlTextNode.textContent += "foo", with selected range on xmlTextNode from 0 to 1 @@ -927,9 +927,9 @@ PASS xmlTextNode.nodeValue = "", with selected range on xmlTextNode from 0 to 1 PASS xmlTextNode.nodeValue = "foo", with unselected range on xmlTextNode from 0 to 1 PASS xmlTextNode.nodeValue = "foo", with selected range on xmlTextNode from 0 to 1 -FAIL xmlTextNode.nodeValue = xmlTextNode.nodeValue, with unselected range on xmlTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS xmlTextNode.nodeValue = xmlTextNode.nodeValue, with unselected range on xmlTextNode from 0 to 1 PASS xmlTextNode.nodeValue = xmlTextNode.nodeValue, with selected range on xmlTextNode from 0 to 1 -FAIL xmlTextNode.nodeValue += "", with unselected range on xmlTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS xmlTextNode.nodeValue += "", with unselected range on xmlTextNode from 0 to 1 PASS xmlTextNode.nodeValue += "", with selected range on xmlTextNode from 0 to 1 PASS xmlTextNode.nodeValue += "foo", with unselected range on xmlTextNode from 0 to 1 PASS xmlTextNode.nodeValue += "foo", with selected range on xmlTextNode from 0 to 1 @@ -939,9 +939,9 @@ PASS xmlTextNode.data = "", with selected range collapsed at (xmlTextNode, 1) PASS xmlTextNode.data = "foo", with unselected range collapsed at (xmlTextNode, 1) PASS xmlTextNode.data = "foo", with selected range collapsed at (xmlTextNode, 1) -FAIL xmlTextNode.data = xmlTextNode.data, with unselected range collapsed at (xmlTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlTextNode.data = xmlTextNode.data, with unselected range collapsed at (xmlTextNode, 1) PASS xmlTextNode.data = xmlTextNode.data, with selected range collapsed at (xmlTextNode, 1) -FAIL xmlTextNode.data += "", with unselected range collapsed at (xmlTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlTextNode.data += "", with unselected range collapsed at (xmlTextNode, 1) PASS xmlTextNode.data += "", with selected range collapsed at (xmlTextNode, 1) PASS xmlTextNode.data += "foo", with unselected range collapsed at (xmlTextNode, 1) PASS xmlTextNode.data += "foo", with selected range collapsed at (xmlTextNode, 1) @@ -951,9 +951,9 @@ PASS xmlTextNode.textContent = "", with selected range collapsed at (xmlTextNode, 1) PASS xmlTextNode.textContent = "foo", with unselected range collapsed at (xmlTextNode, 1) PASS xmlTextNode.textContent = "foo", with selected range collapsed at (xmlTextNode, 1) -FAIL xmlTextNode.textContent = xmlTextNode.textContent, with unselected range collapsed at (xmlTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlTextNode.textContent = xmlTextNode.textContent, with unselected range collapsed at (xmlTextNode, 1) PASS xmlTextNode.textContent = xmlTextNode.textContent, with selected range collapsed at (xmlTextNode, 1) -FAIL xmlTextNode.textContent += "", with unselected range collapsed at (xmlTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlTextNode.textContent += "", with unselected range collapsed at (xmlTextNode, 1) PASS xmlTextNode.textContent += "", with selected range collapsed at (xmlTextNode, 1) PASS xmlTextNode.textContent += "foo", with unselected range collapsed at (xmlTextNode, 1) PASS xmlTextNode.textContent += "foo", with selected range collapsed at (xmlTextNode, 1) @@ -963,9 +963,9 @@ PASS xmlTextNode.nodeValue = "", with selected range collapsed at (xmlTextNode, 1) PASS xmlTextNode.nodeValue = "foo", with unselected range collapsed at (xmlTextNode, 1) PASS xmlTextNode.nodeValue = "foo", with selected range collapsed at (xmlTextNode, 1) -FAIL xmlTextNode.nodeValue = xmlTextNode.nodeValue, with unselected range collapsed at (xmlTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlTextNode.nodeValue = xmlTextNode.nodeValue, with unselected range collapsed at (xmlTextNode, 1) PASS xmlTextNode.nodeValue = xmlTextNode.nodeValue, with selected range collapsed at (xmlTextNode, 1) -FAIL xmlTextNode.nodeValue += "", with unselected range collapsed at (xmlTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlTextNode.nodeValue += "", with unselected range collapsed at (xmlTextNode, 1) PASS xmlTextNode.nodeValue += "", with selected range collapsed at (xmlTextNode, 1) PASS xmlTextNode.nodeValue += "foo", with unselected range collapsed at (xmlTextNode, 1) PASS xmlTextNode.nodeValue += "foo", with selected range collapsed at (xmlTextNode, 1) @@ -975,9 +975,9 @@ PASS xmlTextNode.data = "", with selected range on xmlTextNode from 0 to xmlTextNode.length PASS xmlTextNode.data = "foo", with unselected range on xmlTextNode from 0 to xmlTextNode.length PASS xmlTextNode.data = "foo", with selected range on xmlTextNode from 0 to xmlTextNode.length -FAIL xmlTextNode.data = xmlTextNode.data, with unselected range on xmlTextNode from 0 to xmlTextNode.length assert_equals: Wrong end offset expected 0 but got 20 +PASS xmlTextNode.data = xmlTextNode.data, with unselected range on xmlTextNode from 0 to xmlTextNode.length PASS xmlTextNode.data = xmlTextNode.data, with selected range on xmlTextNode from 0 to xmlTextNode.length -FAIL xmlTextNode.data += "", with unselected range on xmlTextNode from 0 to xmlTextNode.length assert_equals: Wrong end offset expected 0 but got 20 +PASS xmlTextNode.data += "", with unselected range on xmlTextNode from 0 to xmlTextNode.length PASS xmlTextNode.data += "", with selected range on xmlTextNode from 0 to xmlTextNode.length PASS xmlTextNode.data += "foo", with unselected range on xmlTextNode from 0 to xmlTextNode.length PASS xmlTextNode.data += "foo", with selected range on xmlTextNode from 0 to xmlTextNode.length @@ -987,9 +987,9 @@ PASS xmlTextNode.textContent = "", with selected range on xmlTextNode from 0 to xmlTextNode.length PASS xmlTextNode.textContent = "foo", with unselected range on xmlTextNode from 0 to xmlTextNode.length PASS xmlTextNode.textContent = "foo", with selected range on xmlTextNode from 0 to xmlTextNode.length -FAIL xmlTextNode.textContent = xmlTextNode.textContent, with unselected range on xmlTextNode from 0 to xmlTextNode.length assert_equals: Wrong end offset expected 0 but got 20 +PASS xmlTextNode.textContent = xmlTextNode.textContent, with unselected range on xmlTextNode from 0 to xmlTextNode.length PASS xmlTextNode.textContent = xmlTextNode.textContent, with selected range on xmlTextNode from 0 to xmlTextNode.length -FAIL xmlTextNode.textContent += "", with unselected range on xmlTextNode from 0 to xmlTextNode.length assert_equals: Wrong end offset expected 0 but got 20 +PASS xmlTextNode.textContent += "", with unselected range on xmlTextNode from 0 to xmlTextNode.length PASS xmlTextNode.textContent += "", with selected range on xmlTextNode from 0 to xmlTextNode.length PASS xmlTextNode.textContent += "foo", with unselected range on xmlTextNode from 0 to xmlTextNode.length PASS xmlTextNode.textContent += "foo", with selected range on xmlTextNode from 0 to xmlTextNode.length @@ -999,9 +999,9 @@ PASS xmlTextNode.nodeValue = "", with selected range on xmlTextNode from 0 to xmlTextNode.length PASS xmlTextNode.nodeValue = "foo", with unselected range on xmlTextNode from 0 to xmlTextNode.length PASS xmlTextNode.nodeValue = "foo", with selected range on xmlTextNode from 0 to xmlTextNode.length -FAIL xmlTextNode.nodeValue = xmlTextNode.nodeValue, with unselected range on xmlTextNode from 0 to xmlTextNode.length assert_equals: Wrong end offset expected 0 but got 20 +PASS xmlTextNode.nodeValue = xmlTextNode.nodeValue, with unselected range on xmlTextNode from 0 to xmlTextNode.length PASS xmlTextNode.nodeValue = xmlTextNode.nodeValue, with selected range on xmlTextNode from 0 to xmlTextNode.length -FAIL xmlTextNode.nodeValue += "", with unselected range on xmlTextNode from 0 to xmlTextNode.length assert_equals: Wrong end offset expected 0 but got 20 +PASS xmlTextNode.nodeValue += "", with unselected range on xmlTextNode from 0 to xmlTextNode.length PASS xmlTextNode.nodeValue += "", with selected range on xmlTextNode from 0 to xmlTextNode.length PASS xmlTextNode.nodeValue += "foo", with unselected range on xmlTextNode from 0 to xmlTextNode.length PASS xmlTextNode.nodeValue += "foo", with selected range on xmlTextNode from 0 to xmlTextNode.length @@ -1011,9 +1011,9 @@ PASS xmlTextNode.data = "", with selected range on xmlTextNode from 1 to xmlTextNode.length PASS xmlTextNode.data = "foo", with unselected range on xmlTextNode from 1 to xmlTextNode.length PASS xmlTextNode.data = "foo", with selected range on xmlTextNode from 1 to xmlTextNode.length -FAIL xmlTextNode.data = xmlTextNode.data, with unselected range on xmlTextNode from 1 to xmlTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlTextNode.data = xmlTextNode.data, with unselected range on xmlTextNode from 1 to xmlTextNode.length PASS xmlTextNode.data = xmlTextNode.data, with selected range on xmlTextNode from 1 to xmlTextNode.length -FAIL xmlTextNode.data += "", with unselected range on xmlTextNode from 1 to xmlTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlTextNode.data += "", with unselected range on xmlTextNode from 1 to xmlTextNode.length PASS xmlTextNode.data += "", with selected range on xmlTextNode from 1 to xmlTextNode.length PASS xmlTextNode.data += "foo", with unselected range on xmlTextNode from 1 to xmlTextNode.length PASS xmlTextNode.data += "foo", with selected range on xmlTextNode from 1 to xmlTextNode.length @@ -1023,9 +1023,9 @@ PASS xmlTextNode.textContent = "", with selected range on xmlTextNode from 1 to xmlTextNode.length PASS xmlTextNode.textContent = "foo", with unselected range on xmlTextNode from 1 to xmlTextNode.length PASS xmlTextNode.textContent = "foo", with selected range on xmlTextNode from 1 to xmlTextNode.length -FAIL xmlTextNode.textContent = xmlTextNode.textContent, with unselected range on xmlTextNode from 1 to xmlTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlTextNode.textContent = xmlTextNode.textContent, with unselected range on xmlTextNode from 1 to xmlTextNode.length PASS xmlTextNode.textContent = xmlTextNode.textContent, with selected range on xmlTextNode from 1 to xmlTextNode.length -FAIL xmlTextNode.textContent += "", with unselected range on xmlTextNode from 1 to xmlTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlTextNode.textContent += "", with unselected range on xmlTextNode from 1 to xmlTextNode.length PASS xmlTextNode.textContent += "", with selected range on xmlTextNode from 1 to xmlTextNode.length PASS xmlTextNode.textContent += "foo", with unselected range on xmlTextNode from 1 to xmlTextNode.length PASS xmlTextNode.textContent += "foo", with selected range on xmlTextNode from 1 to xmlTextNode.length @@ -1035,9 +1035,9 @@ PASS xmlTextNode.nodeValue = "", with selected range on xmlTextNode from 1 to xmlTextNode.length PASS xmlTextNode.nodeValue = "foo", with unselected range on xmlTextNode from 1 to xmlTextNode.length PASS xmlTextNode.nodeValue = "foo", with selected range on xmlTextNode from 1 to xmlTextNode.length -FAIL xmlTextNode.nodeValue = xmlTextNode.nodeValue, with unselected range on xmlTextNode from 1 to xmlTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlTextNode.nodeValue = xmlTextNode.nodeValue, with unselected range on xmlTextNode from 1 to xmlTextNode.length PASS xmlTextNode.nodeValue = xmlTextNode.nodeValue, with selected range on xmlTextNode from 1 to xmlTextNode.length -FAIL xmlTextNode.nodeValue += "", with unselected range on xmlTextNode from 1 to xmlTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlTextNode.nodeValue += "", with unselected range on xmlTextNode from 1 to xmlTextNode.length PASS xmlTextNode.nodeValue += "", with selected range on xmlTextNode from 1 to xmlTextNode.length PASS xmlTextNode.nodeValue += "foo", with unselected range on xmlTextNode from 1 to xmlTextNode.length PASS xmlTextNode.nodeValue += "foo", with selected range on xmlTextNode from 1 to xmlTextNode.length @@ -1047,9 +1047,9 @@ PASS xmlTextNode.data = "", with selected range collapsed at (xmlTextNode, xmlTextNode.length) PASS xmlTextNode.data = "foo", with unselected range collapsed at (xmlTextNode, xmlTextNode.length) PASS xmlTextNode.data = "foo", with selected range collapsed at (xmlTextNode, xmlTextNode.length) -FAIL xmlTextNode.data = xmlTextNode.data, with unselected range collapsed at (xmlTextNode, xmlTextNode.length) assert_equals: Wrong start offset expected 0 but got 20 +PASS xmlTextNode.data = xmlTextNode.data, with unselected range collapsed at (xmlTextNode, xmlTextNode.length) PASS xmlTextNode.data = xmlTextNode.data, with selected range collapsed at (xmlTextNode, xmlTextNode.length) -FAIL xmlTextNode.data += "", with unselected range collapsed at (xmlTextNode, xmlTextNode.length) assert_equals: Wrong start offset expected 0 but got 20 +PASS xmlTextNode.data += "", with unselected range collapsed at (xmlTextNode, xmlTextNode.length) PASS xmlTextNode.data += "", with selected range collapsed at (xmlTextNode, xmlTextNode.length) PASS xmlTextNode.data += "foo", with unselected range collapsed at (xmlTextNode, xmlTextNode.length) PASS xmlTextNode.data += "foo", with selected range collapsed at (xmlTextNode, xmlTextNode.length) @@ -1059,9 +1059,9 @@ PASS xmlTextNode.textContent = "", with selected range collapsed at (xmlTextNode, xmlTextNode.length) PASS xmlTextNode.textContent = "foo", with unselected range collapsed at (xmlTextNode, xmlTextNode.length) PASS xmlTextNode.textContent = "foo", with selected range collapsed at (xmlTextNode, xmlTextNode.length) -FAIL xmlTextNode.textContent = xmlTextNode.textContent, with unselected range collapsed at (xmlTextNode, xmlTextNode.length) assert_equals: Wrong start offset expected 0 but got 20 +PASS xmlTextNode.textContent = xmlTextNode.textContent, with unselected range collapsed at (xmlTextNode, xmlTextNode.length) PASS xmlTextNode.textContent = xmlTextNode.textContent, with selected range collapsed at (xmlTextNode, xmlTextNode.length) -FAIL xmlTextNode.textContent += "", with unselected range collapsed at (xmlTextNode, xmlTextNode.length) assert_equals: Wrong start offset expected 0 but got 20 +PASS xmlTextNode.textContent += "", with unselected range collapsed at (xmlTextNode, xmlTextNode.length) PASS xmlTextNode.textContent += "", with selected range collapsed at (xmlTextNode, xmlTextNode.length) PASS xmlTextNode.textContent += "foo", with unselected range collapsed at (xmlTextNode, xmlTextNode.length) PASS xmlTextNode.textContent += "foo", with selected range collapsed at (xmlTextNode, xmlTextNode.length) @@ -1071,9 +1071,9 @@ PASS xmlTextNode.nodeValue = "", with selected range collapsed at (xmlTextNode, xmlTextNode.length) PASS xmlTextNode.nodeValue = "foo", with unselected range collapsed at (xmlTextNode, xmlTextNode.length) PASS xmlTextNode.nodeValue = "foo", with selected range collapsed at (xmlTextNode, xmlTextNode.length) -FAIL xmlTextNode.nodeValue = xmlTextNode.nodeValue, with unselected range collapsed at (xmlTextNode, xmlTextNode.length) assert_equals: Wrong start offset expected 0 but got 20 +PASS xmlTextNode.nodeValue = xmlTextNode.nodeValue, with unselected range collapsed at (xmlTextNode, xmlTextNode.length) PASS xmlTextNode.nodeValue = xmlTextNode.nodeValue, with selected range collapsed at (xmlTextNode, xmlTextNode.length) -FAIL xmlTextNode.nodeValue += "", with unselected range collapsed at (xmlTextNode, xmlTextNode.length) assert_equals: Wrong start offset expected 0 but got 20 +PASS xmlTextNode.nodeValue += "", with unselected range collapsed at (xmlTextNode, xmlTextNode.length) PASS xmlTextNode.nodeValue += "", with selected range collapsed at (xmlTextNode, xmlTextNode.length) PASS xmlTextNode.nodeValue += "foo", with unselected range collapsed at (xmlTextNode, xmlTextNode.length) PASS xmlTextNode.nodeValue += "foo", with selected range collapsed at (xmlTextNode, xmlTextNode.length) @@ -1119,9 +1119,9 @@ PASS detachedTextNode.data = "", with selected range on detachedTextNode from 0 to 1 PASS detachedTextNode.data = "foo", with unselected range on detachedTextNode from 0 to 1 PASS detachedTextNode.data = "foo", with selected range on detachedTextNode from 0 to 1 -FAIL detachedTextNode.data = detachedTextNode.data, with unselected range on detachedTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedTextNode.data = detachedTextNode.data, with unselected range on detachedTextNode from 0 to 1 PASS detachedTextNode.data = detachedTextNode.data, with selected range on detachedTextNode from 0 to 1 -FAIL detachedTextNode.data += "", with unselected range on detachedTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedTextNode.data += "", with unselected range on detachedTextNode from 0 to 1 PASS detachedTextNode.data += "", with selected range on detachedTextNode from 0 to 1 PASS detachedTextNode.data += "foo", with unselected range on detachedTextNode from 0 to 1 PASS detachedTextNode.data += "foo", with selected range on detachedTextNode from 0 to 1 @@ -1131,9 +1131,9 @@ PASS detachedTextNode.textContent = "", with selected range on detachedTextNode from 0 to 1 PASS detachedTextNode.textContent = "foo", with unselected range on detachedTextNode from 0 to 1 PASS detachedTextNode.textContent = "foo", with selected range on detachedTextNode from 0 to 1 -FAIL detachedTextNode.textContent = detachedTextNode.textContent, with unselected range on detachedTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedTextNode.textContent = detachedTextNode.textContent, with unselected range on detachedTextNode from 0 to 1 PASS detachedTextNode.textContent = detachedTextNode.textContent, with selected range on detachedTextNode from 0 to 1 -FAIL detachedTextNode.textContent += "", with unselected range on detachedTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedTextNode.textContent += "", with unselected range on detachedTextNode from 0 to 1 PASS detachedTextNode.textContent += "", with selected range on detachedTextNode from 0 to 1 PASS detachedTextNode.textContent += "foo", with unselected range on detachedTextNode from 0 to 1 PASS detachedTextNode.textContent += "foo", with selected range on detachedTextNode from 0 to 1 @@ -1143,9 +1143,9 @@ PASS detachedTextNode.nodeValue = "", with selected range on detachedTextNode from 0 to 1 PASS detachedTextNode.nodeValue = "foo", with unselected range on detachedTextNode from 0 to 1 PASS detachedTextNode.nodeValue = "foo", with selected range on detachedTextNode from 0 to 1 -FAIL detachedTextNode.nodeValue = detachedTextNode.nodeValue, with unselected range on detachedTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedTextNode.nodeValue = detachedTextNode.nodeValue, with unselected range on detachedTextNode from 0 to 1 PASS detachedTextNode.nodeValue = detachedTextNode.nodeValue, with selected range on detachedTextNode from 0 to 1 -FAIL detachedTextNode.nodeValue += "", with unselected range on detachedTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedTextNode.nodeValue += "", with unselected range on detachedTextNode from 0 to 1 PASS detachedTextNode.nodeValue += "", with selected range on detachedTextNode from 0 to 1 PASS detachedTextNode.nodeValue += "foo", with unselected range on detachedTextNode from 0 to 1 PASS detachedTextNode.nodeValue += "foo", with selected range on detachedTextNode from 0 to 1 @@ -1155,9 +1155,9 @@ PASS detachedTextNode.data = "", with selected range collapsed at (detachedTextNode, 1) PASS detachedTextNode.data = "foo", with unselected range collapsed at (detachedTextNode, 1) PASS detachedTextNode.data = "foo", with selected range collapsed at (detachedTextNode, 1) -FAIL detachedTextNode.data = detachedTextNode.data, with unselected range collapsed at (detachedTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedTextNode.data = detachedTextNode.data, with unselected range collapsed at (detachedTextNode, 1) PASS detachedTextNode.data = detachedTextNode.data, with selected range collapsed at (detachedTextNode, 1) -FAIL detachedTextNode.data += "", with unselected range collapsed at (detachedTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedTextNode.data += "", with unselected range collapsed at (detachedTextNode, 1) PASS detachedTextNode.data += "", with selected range collapsed at (detachedTextNode, 1) PASS detachedTextNode.data += "foo", with unselected range collapsed at (detachedTextNode, 1) PASS detachedTextNode.data += "foo", with selected range collapsed at (detachedTextNode, 1) @@ -1167,9 +1167,9 @@ PASS detachedTextNode.textContent = "", with selected range collapsed at (detachedTextNode, 1) PASS detachedTextNode.textContent = "foo", with unselected range collapsed at (detachedTextNode, 1) PASS detachedTextNode.textContent = "foo", with selected range collapsed at (detachedTextNode, 1) -FAIL detachedTextNode.textContent = detachedTextNode.textContent, with unselected range collapsed at (detachedTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedTextNode.textContent = detachedTextNode.textContent, with unselected range collapsed at (detachedTextNode, 1) PASS detachedTextNode.textContent = detachedTextNode.textContent, with selected range collapsed at (detachedTextNode, 1) -FAIL detachedTextNode.textContent += "", with unselected range collapsed at (detachedTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedTextNode.textContent += "", with unselected range collapsed at (detachedTextNode, 1) PASS detachedTextNode.textContent += "", with selected range collapsed at (detachedTextNode, 1) PASS detachedTextNode.textContent += "foo", with unselected range collapsed at (detachedTextNode, 1) PASS detachedTextNode.textContent += "foo", with selected range collapsed at (detachedTextNode, 1) @@ -1179,9 +1179,9 @@ PASS detachedTextNode.nodeValue = "", with selected range collapsed at (detachedTextNode, 1) PASS detachedTextNode.nodeValue = "foo", with unselected range collapsed at (detachedTextNode, 1) PASS detachedTextNode.nodeValue = "foo", with selected range collapsed at (detachedTextNode, 1) -FAIL detachedTextNode.nodeValue = detachedTextNode.nodeValue, with unselected range collapsed at (detachedTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedTextNode.nodeValue = detachedTextNode.nodeValue, with unselected range collapsed at (detachedTextNode, 1) PASS detachedTextNode.nodeValue = detachedTextNode.nodeValue, with selected range collapsed at (detachedTextNode, 1) -FAIL detachedTextNode.nodeValue += "", with unselected range collapsed at (detachedTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedTextNode.nodeValue += "", with unselected range collapsed at (detachedTextNode, 1) PASS detachedTextNode.nodeValue += "", with selected range collapsed at (detachedTextNode, 1) PASS detachedTextNode.nodeValue += "foo", with unselected range collapsed at (detachedTextNode, 1) PASS detachedTextNode.nodeValue += "foo", with selected range collapsed at (detachedTextNode, 1) @@ -1191,9 +1191,9 @@ PASS detachedTextNode.data = "", with selected range on detachedTextNode from 0 to detachedTextNode.length PASS detachedTextNode.data = "foo", with unselected range on detachedTextNode from 0 to detachedTextNode.length PASS detachedTextNode.data = "foo", with selected range on detachedTextNode from 0 to detachedTextNode.length -FAIL detachedTextNode.data = detachedTextNode.data, with unselected range on detachedTextNode from 0 to detachedTextNode.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedTextNode.data = detachedTextNode.data, with unselected range on detachedTextNode from 0 to detachedTextNode.length PASS detachedTextNode.data = detachedTextNode.data, with selected range on detachedTextNode from 0 to detachedTextNode.length -FAIL detachedTextNode.data += "", with unselected range on detachedTextNode from 0 to detachedTextNode.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedTextNode.data += "", with unselected range on detachedTextNode from 0 to detachedTextNode.length PASS detachedTextNode.data += "", with selected range on detachedTextNode from 0 to detachedTextNode.length PASS detachedTextNode.data += "foo", with unselected range on detachedTextNode from 0 to detachedTextNode.length PASS detachedTextNode.data += "foo", with selected range on detachedTextNode from 0 to detachedTextNode.length @@ -1203,9 +1203,9 @@ PASS detachedTextNode.textContent = "", with selected range on detachedTextNode from 0 to detachedTextNode.length PASS detachedTextNode.textContent = "foo", with unselected range on detachedTextNode from 0 to detachedTextNode.length PASS detachedTextNode.textContent = "foo", with selected range on detachedTextNode from 0 to detachedTextNode.length -FAIL detachedTextNode.textContent = detachedTextNode.textContent, with unselected range on detachedTextNode from 0 to detachedTextNode.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedTextNode.textContent = detachedTextNode.textContent, with unselected range on detachedTextNode from 0 to detachedTextNode.length PASS detachedTextNode.textContent = detachedTextNode.textContent, with selected range on detachedTextNode from 0 to detachedTextNode.length -FAIL detachedTextNode.textContent += "", with unselected range on detachedTextNode from 0 to detachedTextNode.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedTextNode.textContent += "", with unselected range on detachedTextNode from 0 to detachedTextNode.length PASS detachedTextNode.textContent += "", with selected range on detachedTextNode from 0 to detachedTextNode.length PASS detachedTextNode.textContent += "foo", with unselected range on detachedTextNode from 0 to detachedTextNode.length PASS detachedTextNode.textContent += "foo", with selected range on detachedTextNode from 0 to detachedTextNode.length @@ -1215,9 +1215,9 @@ PASS detachedTextNode.nodeValue = "", with selected range on detachedTextNode from 0 to detachedTextNode.length PASS detachedTextNode.nodeValue = "foo", with unselected range on detachedTextNode from 0 to detachedTextNode.length PASS detachedTextNode.nodeValue = "foo", with selected range on detachedTextNode from 0 to detachedTextNode.length -FAIL detachedTextNode.nodeValue = detachedTextNode.nodeValue, with unselected range on detachedTextNode from 0 to detachedTextNode.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedTextNode.nodeValue = detachedTextNode.nodeValue, with unselected range on detachedTextNode from 0 to detachedTextNode.length PASS detachedTextNode.nodeValue = detachedTextNode.nodeValue, with selected range on detachedTextNode from 0 to detachedTextNode.length -FAIL detachedTextNode.nodeValue += "", with unselected range on detachedTextNode from 0 to detachedTextNode.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedTextNode.nodeValue += "", with unselected range on detachedTextNode from 0 to detachedTextNode.length PASS detachedTextNode.nodeValue += "", with selected range on detachedTextNode from 0 to detachedTextNode.length PASS detachedTextNode.nodeValue += "foo", with unselected range on detachedTextNode from 0 to detachedTextNode.length PASS detachedTextNode.nodeValue += "foo", with selected range on detachedTextNode from 0 to detachedTextNode.length @@ -1227,9 +1227,9 @@ PASS detachedTextNode.data = "", with selected range on detachedTextNode from 1 to detachedTextNode.length PASS detachedTextNode.data = "foo", with unselected range on detachedTextNode from 1 to detachedTextNode.length PASS detachedTextNode.data = "foo", with selected range on detachedTextNode from 1 to detachedTextNode.length -FAIL detachedTextNode.data = detachedTextNode.data, with unselected range on detachedTextNode from 1 to detachedTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedTextNode.data = detachedTextNode.data, with unselected range on detachedTextNode from 1 to detachedTextNode.length PASS detachedTextNode.data = detachedTextNode.data, with selected range on detachedTextNode from 1 to detachedTextNode.length -FAIL detachedTextNode.data += "", with unselected range on detachedTextNode from 1 to detachedTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedTextNode.data += "", with unselected range on detachedTextNode from 1 to detachedTextNode.length PASS detachedTextNode.data += "", with selected range on detachedTextNode from 1 to detachedTextNode.length PASS detachedTextNode.data += "foo", with unselected range on detachedTextNode from 1 to detachedTextNode.length PASS detachedTextNode.data += "foo", with selected range on detachedTextNode from 1 to detachedTextNode.length @@ -1239,9 +1239,9 @@ PASS detachedTextNode.textContent = "", with selected range on detachedTextNode from 1 to detachedTextNode.length PASS detachedTextNode.textContent = "foo", with unselected range on detachedTextNode from 1 to detachedTextNode.length PASS detachedTextNode.textContent = "foo", with selected range on detachedTextNode from 1 to detachedTextNode.length -FAIL detachedTextNode.textContent = detachedTextNode.textContent, with unselected range on detachedTextNode from 1 to detachedTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedTextNode.textContent = detachedTextNode.textContent, with unselected range on detachedTextNode from 1 to detachedTextNode.length PASS detachedTextNode.textContent = detachedTextNode.textContent, with selected range on detachedTextNode from 1 to detachedTextNode.length -FAIL detachedTextNode.textContent += "", with unselected range on detachedTextNode from 1 to detachedTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedTextNode.textContent += "", with unselected range on detachedTextNode from 1 to detachedTextNode.length PASS detachedTextNode.textContent += "", with selected range on detachedTextNode from 1 to detachedTextNode.length PASS detachedTextNode.textContent += "foo", with unselected range on detachedTextNode from 1 to detachedTextNode.length PASS detachedTextNode.textContent += "foo", with selected range on detachedTextNode from 1 to detachedTextNode.length @@ -1251,9 +1251,9 @@ PASS detachedTextNode.nodeValue = "", with selected range on detachedTextNode from 1 to detachedTextNode.length PASS detachedTextNode.nodeValue = "foo", with unselected range on detachedTextNode from 1 to detachedTextNode.length PASS detachedTextNode.nodeValue = "foo", with selected range on detachedTextNode from 1 to detachedTextNode.length -FAIL detachedTextNode.nodeValue = detachedTextNode.nodeValue, with unselected range on detachedTextNode from 1 to detachedTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedTextNode.nodeValue = detachedTextNode.nodeValue, with unselected range on detachedTextNode from 1 to detachedTextNode.length PASS detachedTextNode.nodeValue = detachedTextNode.nodeValue, with selected range on detachedTextNode from 1 to detachedTextNode.length -FAIL detachedTextNode.nodeValue += "", with unselected range on detachedTextNode from 1 to detachedTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedTextNode.nodeValue += "", with unselected range on detachedTextNode from 1 to detachedTextNode.length PASS detachedTextNode.nodeValue += "", with selected range on detachedTextNode from 1 to detachedTextNode.length PASS detachedTextNode.nodeValue += "foo", with unselected range on detachedTextNode from 1 to detachedTextNode.length PASS detachedTextNode.nodeValue += "foo", with selected range on detachedTextNode from 1 to detachedTextNode.length @@ -1263,9 +1263,9 @@ PASS detachedTextNode.data = "", with selected range collapsed at (detachedTextNode, detachedTextNode.length) PASS detachedTextNode.data = "foo", with unselected range collapsed at (detachedTextNode, detachedTextNode.length) PASS detachedTextNode.data = "foo", with selected range collapsed at (detachedTextNode, detachedTextNode.length) -FAIL detachedTextNode.data = detachedTextNode.data, with unselected range collapsed at (detachedTextNode, detachedTextNode.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedTextNode.data = detachedTextNode.data, with unselected range collapsed at (detachedTextNode, detachedTextNode.length) PASS detachedTextNode.data = detachedTextNode.data, with selected range collapsed at (detachedTextNode, detachedTextNode.length) -FAIL detachedTextNode.data += "", with unselected range collapsed at (detachedTextNode, detachedTextNode.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedTextNode.data += "", with unselected range collapsed at (detachedTextNode, detachedTextNode.length) PASS detachedTextNode.data += "", with selected range collapsed at (detachedTextNode, detachedTextNode.length) PASS detachedTextNode.data += "foo", with unselected range collapsed at (detachedTextNode, detachedTextNode.length) PASS detachedTextNode.data += "foo", with selected range collapsed at (detachedTextNode, detachedTextNode.length) @@ -1275,9 +1275,9 @@ PASS detachedTextNode.textContent = "", with selected range collapsed at (detachedTextNode, detachedTextNode.length) PASS detachedTextNode.textContent = "foo", with unselected range collapsed at (detachedTextNode, detachedTextNode.length) PASS detachedTextNode.textContent = "foo", with selected range collapsed at (detachedTextNode, detachedTextNode.length) -FAIL detachedTextNode.textContent = detachedTextNode.textContent, with unselected range collapsed at (detachedTextNode, detachedTextNode.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedTextNode.textContent = detachedTextNode.textContent, with unselected range collapsed at (detachedTextNode, detachedTextNode.length) PASS detachedTextNode.textContent = detachedTextNode.textContent, with selected range collapsed at (detachedTextNode, detachedTextNode.length) -FAIL detachedTextNode.textContent += "", with unselected range collapsed at (detachedTextNode, detachedTextNode.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedTextNode.textContent += "", with unselected range collapsed at (detachedTextNode, detachedTextNode.length) PASS detachedTextNode.textContent += "", with selected range collapsed at (detachedTextNode, detachedTextNode.length) PASS detachedTextNode.textContent += "foo", with unselected range collapsed at (detachedTextNode, detachedTextNode.length) PASS detachedTextNode.textContent += "foo", with selected range collapsed at (detachedTextNode, detachedTextNode.length) @@ -1287,9 +1287,9 @@ PASS detachedTextNode.nodeValue = "", with selected range collapsed at (detachedTextNode, detachedTextNode.length) PASS detachedTextNode.nodeValue = "foo", with unselected range collapsed at (detachedTextNode, detachedTextNode.length) PASS detachedTextNode.nodeValue = "foo", with selected range collapsed at (detachedTextNode, detachedTextNode.length) -FAIL detachedTextNode.nodeValue = detachedTextNode.nodeValue, with unselected range collapsed at (detachedTextNode, detachedTextNode.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedTextNode.nodeValue = detachedTextNode.nodeValue, with unselected range collapsed at (detachedTextNode, detachedTextNode.length) PASS detachedTextNode.nodeValue = detachedTextNode.nodeValue, with selected range collapsed at (detachedTextNode, detachedTextNode.length) -FAIL detachedTextNode.nodeValue += "", with unselected range collapsed at (detachedTextNode, detachedTextNode.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedTextNode.nodeValue += "", with unselected range collapsed at (detachedTextNode, detachedTextNode.length) PASS detachedTextNode.nodeValue += "", with selected range collapsed at (detachedTextNode, detachedTextNode.length) PASS detachedTextNode.nodeValue += "foo", with unselected range collapsed at (detachedTextNode, detachedTextNode.length) PASS detachedTextNode.nodeValue += "foo", with selected range collapsed at (detachedTextNode, detachedTextNode.length) @@ -1335,9 +1335,9 @@ PASS detachedForeignTextNode.data = "", with selected range on detachedForeignTextNode from 0 to 1 PASS detachedForeignTextNode.data = "foo", with unselected range on detachedForeignTextNode from 0 to 1 PASS detachedForeignTextNode.data = "foo", with selected range on detachedForeignTextNode from 0 to 1 -FAIL detachedForeignTextNode.data = detachedForeignTextNode.data, with unselected range on detachedForeignTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedForeignTextNode.data = detachedForeignTextNode.data, with unselected range on detachedForeignTextNode from 0 to 1 PASS detachedForeignTextNode.data = detachedForeignTextNode.data, with selected range on detachedForeignTextNode from 0 to 1 -FAIL detachedForeignTextNode.data += "", with unselected range on detachedForeignTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedForeignTextNode.data += "", with unselected range on detachedForeignTextNode from 0 to 1 PASS detachedForeignTextNode.data += "", with selected range on detachedForeignTextNode from 0 to 1 PASS detachedForeignTextNode.data += "foo", with unselected range on detachedForeignTextNode from 0 to 1 PASS detachedForeignTextNode.data += "foo", with selected range on detachedForeignTextNode from 0 to 1 @@ -1347,9 +1347,9 @@ PASS detachedForeignTextNode.textContent = "", with selected range on detachedForeignTextNode from 0 to 1 PASS detachedForeignTextNode.textContent = "foo", with unselected range on detachedForeignTextNode from 0 to 1 PASS detachedForeignTextNode.textContent = "foo", with selected range on detachedForeignTextNode from 0 to 1 -FAIL detachedForeignTextNode.textContent = detachedForeignTextNode.textContent, with unselected range on detachedForeignTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedForeignTextNode.textContent = detachedForeignTextNode.textContent, with unselected range on detachedForeignTextNode from 0 to 1 PASS detachedForeignTextNode.textContent = detachedForeignTextNode.textContent, with selected range on detachedForeignTextNode from 0 to 1 -FAIL detachedForeignTextNode.textContent += "", with unselected range on detachedForeignTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedForeignTextNode.textContent += "", with unselected range on detachedForeignTextNode from 0 to 1 PASS detachedForeignTextNode.textContent += "", with selected range on detachedForeignTextNode from 0 to 1 PASS detachedForeignTextNode.textContent += "foo", with unselected range on detachedForeignTextNode from 0 to 1 PASS detachedForeignTextNode.textContent += "foo", with selected range on detachedForeignTextNode from 0 to 1 @@ -1359,9 +1359,9 @@ PASS detachedForeignTextNode.nodeValue = "", with selected range on detachedForeignTextNode from 0 to 1 PASS detachedForeignTextNode.nodeValue = "foo", with unselected range on detachedForeignTextNode from 0 to 1 PASS detachedForeignTextNode.nodeValue = "foo", with selected range on detachedForeignTextNode from 0 to 1 -FAIL detachedForeignTextNode.nodeValue = detachedForeignTextNode.nodeValue, with unselected range on detachedForeignTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedForeignTextNode.nodeValue = detachedForeignTextNode.nodeValue, with unselected range on detachedForeignTextNode from 0 to 1 PASS detachedForeignTextNode.nodeValue = detachedForeignTextNode.nodeValue, with selected range on detachedForeignTextNode from 0 to 1 -FAIL detachedForeignTextNode.nodeValue += "", with unselected range on detachedForeignTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedForeignTextNode.nodeValue += "", with unselected range on detachedForeignTextNode from 0 to 1 PASS detachedForeignTextNode.nodeValue += "", with selected range on detachedForeignTextNode from 0 to 1 PASS detachedForeignTextNode.nodeValue += "foo", with unselected range on detachedForeignTextNode from 0 to 1 PASS detachedForeignTextNode.nodeValue += "foo", with selected range on detachedForeignTextNode from 0 to 1 @@ -1371,9 +1371,9 @@ PASS detachedForeignTextNode.data = "", with selected range collapsed at (detachedForeignTextNode, 1) PASS detachedForeignTextNode.data = "foo", with unselected range collapsed at (detachedForeignTextNode, 1) PASS detachedForeignTextNode.data = "foo", with selected range collapsed at (detachedForeignTextNode, 1) -FAIL detachedForeignTextNode.data = detachedForeignTextNode.data, with unselected range collapsed at (detachedForeignTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignTextNode.data = detachedForeignTextNode.data, with unselected range collapsed at (detachedForeignTextNode, 1) PASS detachedForeignTextNode.data = detachedForeignTextNode.data, with selected range collapsed at (detachedForeignTextNode, 1) -FAIL detachedForeignTextNode.data += "", with unselected range collapsed at (detachedForeignTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignTextNode.data += "", with unselected range collapsed at (detachedForeignTextNode, 1) PASS detachedForeignTextNode.data += "", with selected range collapsed at (detachedForeignTextNode, 1) PASS detachedForeignTextNode.data += "foo", with unselected range collapsed at (detachedForeignTextNode, 1) PASS detachedForeignTextNode.data += "foo", with selected range collapsed at (detachedForeignTextNode, 1) @@ -1383,9 +1383,9 @@ PASS detachedForeignTextNode.textContent = "", with selected range collapsed at (detachedForeignTextNode, 1) PASS detachedForeignTextNode.textContent = "foo", with unselected range collapsed at (detachedForeignTextNode, 1) PASS detachedForeignTextNode.textContent = "foo", with selected range collapsed at (detachedForeignTextNode, 1) -FAIL detachedForeignTextNode.textContent = detachedForeignTextNode.textContent, with unselected range collapsed at (detachedForeignTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignTextNode.textContent = detachedForeignTextNode.textContent, with unselected range collapsed at (detachedForeignTextNode, 1) PASS detachedForeignTextNode.textContent = detachedForeignTextNode.textContent, with selected range collapsed at (detachedForeignTextNode, 1) -FAIL detachedForeignTextNode.textContent += "", with unselected range collapsed at (detachedForeignTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignTextNode.textContent += "", with unselected range collapsed at (detachedForeignTextNode, 1) PASS detachedForeignTextNode.textContent += "", with selected range collapsed at (detachedForeignTextNode, 1) PASS detachedForeignTextNode.textContent += "foo", with unselected range collapsed at (detachedForeignTextNode, 1) PASS detachedForeignTextNode.textContent += "foo", with selected range collapsed at (detachedForeignTextNode, 1) @@ -1395,9 +1395,9 @@ PASS detachedForeignTextNode.nodeValue = "", with selected range collapsed at (detachedForeignTextNode, 1) PASS detachedForeignTextNode.nodeValue = "foo", with unselected range collapsed at (detachedForeignTextNode, 1) PASS detachedForeignTextNode.nodeValue = "foo", with selected range collapsed at (detachedForeignTextNode, 1) -FAIL detachedForeignTextNode.nodeValue = detachedForeignTextNode.nodeValue, with unselected range collapsed at (detachedForeignTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignTextNode.nodeValue = detachedForeignTextNode.nodeValue, with unselected range collapsed at (detachedForeignTextNode, 1) PASS detachedForeignTextNode.nodeValue = detachedForeignTextNode.nodeValue, with selected range collapsed at (detachedForeignTextNode, 1) -FAIL detachedForeignTextNode.nodeValue += "", with unselected range collapsed at (detachedForeignTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignTextNode.nodeValue += "", with unselected range collapsed at (detachedForeignTextNode, 1) PASS detachedForeignTextNode.nodeValue += "", with selected range collapsed at (detachedForeignTextNode, 1) PASS detachedForeignTextNode.nodeValue += "foo", with unselected range collapsed at (detachedForeignTextNode, 1) PASS detachedForeignTextNode.nodeValue += "foo", with selected range collapsed at (detachedForeignTextNode, 1) @@ -1407,9 +1407,9 @@ PASS detachedForeignTextNode.data = "", with selected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length PASS detachedForeignTextNode.data = "foo", with unselected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length PASS detachedForeignTextNode.data = "foo", with selected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length -FAIL detachedForeignTextNode.data = detachedForeignTextNode.data, with unselected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedForeignTextNode.data = detachedForeignTextNode.data, with unselected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length PASS detachedForeignTextNode.data = detachedForeignTextNode.data, with selected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length -FAIL detachedForeignTextNode.data += "", with unselected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedForeignTextNode.data += "", with unselected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length PASS detachedForeignTextNode.data += "", with selected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length PASS detachedForeignTextNode.data += "foo", with unselected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length PASS detachedForeignTextNode.data += "foo", with selected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length @@ -1419,9 +1419,9 @@ PASS detachedForeignTextNode.textContent = "", with selected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length PASS detachedForeignTextNode.textContent = "foo", with unselected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length PASS detachedForeignTextNode.textContent = "foo", with selected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length -FAIL detachedForeignTextNode.textContent = detachedForeignTextNode.textContent, with unselected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedForeignTextNode.textContent = detachedForeignTextNode.textContent, with unselected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length PASS detachedForeignTextNode.textContent = detachedForeignTextNode.textContent, with selected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length -FAIL detachedForeignTextNode.textContent += "", with unselected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedForeignTextNode.textContent += "", with unselected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length PASS detachedForeignTextNode.textContent += "", with selected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length PASS detachedForeignTextNode.textContent += "foo", with unselected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length PASS detachedForeignTextNode.textContent += "foo", with selected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length @@ -1431,9 +1431,9 @@ PASS detachedForeignTextNode.nodeValue = "", with selected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length PASS detachedForeignTextNode.nodeValue = "foo", with unselected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length PASS detachedForeignTextNode.nodeValue = "foo", with selected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length -FAIL detachedForeignTextNode.nodeValue = detachedForeignTextNode.nodeValue, with unselected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedForeignTextNode.nodeValue = detachedForeignTextNode.nodeValue, with unselected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length PASS detachedForeignTextNode.nodeValue = detachedForeignTextNode.nodeValue, with selected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length -FAIL detachedForeignTextNode.nodeValue += "", with unselected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedForeignTextNode.nodeValue += "", with unselected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length PASS detachedForeignTextNode.nodeValue += "", with selected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length PASS detachedForeignTextNode.nodeValue += "foo", with unselected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length PASS detachedForeignTextNode.nodeValue += "foo", with selected range on detachedForeignTextNode from 0 to detachedForeignTextNode.length @@ -1443,9 +1443,9 @@ PASS detachedForeignTextNode.data = "", with selected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length PASS detachedForeignTextNode.data = "foo", with unselected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length PASS detachedForeignTextNode.data = "foo", with selected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length -FAIL detachedForeignTextNode.data = detachedForeignTextNode.data, with unselected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignTextNode.data = detachedForeignTextNode.data, with unselected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length PASS detachedForeignTextNode.data = detachedForeignTextNode.data, with selected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length -FAIL detachedForeignTextNode.data += "", with unselected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignTextNode.data += "", with unselected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length PASS detachedForeignTextNode.data += "", with selected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length PASS detachedForeignTextNode.data += "foo", with unselected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length PASS detachedForeignTextNode.data += "foo", with selected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length @@ -1455,9 +1455,9 @@ PASS detachedForeignTextNode.textContent = "", with selected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length PASS detachedForeignTextNode.textContent = "foo", with unselected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length PASS detachedForeignTextNode.textContent = "foo", with selected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length -FAIL detachedForeignTextNode.textContent = detachedForeignTextNode.textContent, with unselected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignTextNode.textContent = detachedForeignTextNode.textContent, with unselected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length PASS detachedForeignTextNode.textContent = detachedForeignTextNode.textContent, with selected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length -FAIL detachedForeignTextNode.textContent += "", with unselected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignTextNode.textContent += "", with unselected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length PASS detachedForeignTextNode.textContent += "", with selected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length PASS detachedForeignTextNode.textContent += "foo", with unselected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length PASS detachedForeignTextNode.textContent += "foo", with selected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length @@ -1467,9 +1467,9 @@ PASS detachedForeignTextNode.nodeValue = "", with selected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length PASS detachedForeignTextNode.nodeValue = "foo", with unselected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length PASS detachedForeignTextNode.nodeValue = "foo", with selected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length -FAIL detachedForeignTextNode.nodeValue = detachedForeignTextNode.nodeValue, with unselected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignTextNode.nodeValue = detachedForeignTextNode.nodeValue, with unselected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length PASS detachedForeignTextNode.nodeValue = detachedForeignTextNode.nodeValue, with selected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length -FAIL detachedForeignTextNode.nodeValue += "", with unselected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignTextNode.nodeValue += "", with unselected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length PASS detachedForeignTextNode.nodeValue += "", with selected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length PASS detachedForeignTextNode.nodeValue += "foo", with unselected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length PASS detachedForeignTextNode.nodeValue += "foo", with selected range on detachedForeignTextNode from 1 to detachedForeignTextNode.length @@ -1479,9 +1479,9 @@ PASS detachedForeignTextNode.data = "", with selected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) PASS detachedForeignTextNode.data = "foo", with unselected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) PASS detachedForeignTextNode.data = "foo", with selected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) -FAIL detachedForeignTextNode.data = detachedForeignTextNode.data, with unselected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedForeignTextNode.data = detachedForeignTextNode.data, with unselected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) PASS detachedForeignTextNode.data = detachedForeignTextNode.data, with selected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) -FAIL detachedForeignTextNode.data += "", with unselected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedForeignTextNode.data += "", with unselected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) PASS detachedForeignTextNode.data += "", with selected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) PASS detachedForeignTextNode.data += "foo", with unselected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) PASS detachedForeignTextNode.data += "foo", with selected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) @@ -1491,9 +1491,9 @@ PASS detachedForeignTextNode.textContent = "", with selected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) PASS detachedForeignTextNode.textContent = "foo", with unselected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) PASS detachedForeignTextNode.textContent = "foo", with selected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) -FAIL detachedForeignTextNode.textContent = detachedForeignTextNode.textContent, with unselected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedForeignTextNode.textContent = detachedForeignTextNode.textContent, with unselected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) PASS detachedForeignTextNode.textContent = detachedForeignTextNode.textContent, with selected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) -FAIL detachedForeignTextNode.textContent += "", with unselected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedForeignTextNode.textContent += "", with unselected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) PASS detachedForeignTextNode.textContent += "", with selected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) PASS detachedForeignTextNode.textContent += "foo", with unselected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) PASS detachedForeignTextNode.textContent += "foo", with selected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) @@ -1503,9 +1503,9 @@ PASS detachedForeignTextNode.nodeValue = "", with selected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) PASS detachedForeignTextNode.nodeValue = "foo", with unselected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) PASS detachedForeignTextNode.nodeValue = "foo", with selected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) -FAIL detachedForeignTextNode.nodeValue = detachedForeignTextNode.nodeValue, with unselected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedForeignTextNode.nodeValue = detachedForeignTextNode.nodeValue, with unselected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) PASS detachedForeignTextNode.nodeValue = detachedForeignTextNode.nodeValue, with selected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) -FAIL detachedForeignTextNode.nodeValue += "", with unselected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedForeignTextNode.nodeValue += "", with unselected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) PASS detachedForeignTextNode.nodeValue += "", with selected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) PASS detachedForeignTextNode.nodeValue += "foo", with unselected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) PASS detachedForeignTextNode.nodeValue += "foo", with selected range collapsed at (detachedForeignTextNode, detachedForeignTextNode.length) @@ -1551,9 +1551,9 @@ PASS detachedXmlTextNode.data = "", with selected range on detachedXmlTextNode from 0 to 1 PASS detachedXmlTextNode.data = "foo", with unselected range on detachedXmlTextNode from 0 to 1 PASS detachedXmlTextNode.data = "foo", with selected range on detachedXmlTextNode from 0 to 1 -FAIL detachedXmlTextNode.data = detachedXmlTextNode.data, with unselected range on detachedXmlTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedXmlTextNode.data = detachedXmlTextNode.data, with unselected range on detachedXmlTextNode from 0 to 1 PASS detachedXmlTextNode.data = detachedXmlTextNode.data, with selected range on detachedXmlTextNode from 0 to 1 -FAIL detachedXmlTextNode.data += "", with unselected range on detachedXmlTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedXmlTextNode.data += "", with unselected range on detachedXmlTextNode from 0 to 1 PASS detachedXmlTextNode.data += "", with selected range on detachedXmlTextNode from 0 to 1 PASS detachedXmlTextNode.data += "foo", with unselected range on detachedXmlTextNode from 0 to 1 PASS detachedXmlTextNode.data += "foo", with selected range on detachedXmlTextNode from 0 to 1 @@ -1563,9 +1563,9 @@ PASS detachedXmlTextNode.textContent = "", with selected range on detachedXmlTextNode from 0 to 1 PASS detachedXmlTextNode.textContent = "foo", with unselected range on detachedXmlTextNode from 0 to 1 PASS detachedXmlTextNode.textContent = "foo", with selected range on detachedXmlTextNode from 0 to 1 -FAIL detachedXmlTextNode.textContent = detachedXmlTextNode.textContent, with unselected range on detachedXmlTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedXmlTextNode.textContent = detachedXmlTextNode.textContent, with unselected range on detachedXmlTextNode from 0 to 1 PASS detachedXmlTextNode.textContent = detachedXmlTextNode.textContent, with selected range on detachedXmlTextNode from 0 to 1 -FAIL detachedXmlTextNode.textContent += "", with unselected range on detachedXmlTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedXmlTextNode.textContent += "", with unselected range on detachedXmlTextNode from 0 to 1 PASS detachedXmlTextNode.textContent += "", with selected range on detachedXmlTextNode from 0 to 1 PASS detachedXmlTextNode.textContent += "foo", with unselected range on detachedXmlTextNode from 0 to 1 PASS detachedXmlTextNode.textContent += "foo", with selected range on detachedXmlTextNode from 0 to 1 @@ -1575,9 +1575,9 @@ PASS detachedXmlTextNode.nodeValue = "", with selected range on detachedXmlTextNode from 0 to 1 PASS detachedXmlTextNode.nodeValue = "foo", with unselected range on detachedXmlTextNode from 0 to 1 PASS detachedXmlTextNode.nodeValue = "foo", with selected range on detachedXmlTextNode from 0 to 1 -FAIL detachedXmlTextNode.nodeValue = detachedXmlTextNode.nodeValue, with unselected range on detachedXmlTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedXmlTextNode.nodeValue = detachedXmlTextNode.nodeValue, with unselected range on detachedXmlTextNode from 0 to 1 PASS detachedXmlTextNode.nodeValue = detachedXmlTextNode.nodeValue, with selected range on detachedXmlTextNode from 0 to 1 -FAIL detachedXmlTextNode.nodeValue += "", with unselected range on detachedXmlTextNode from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedXmlTextNode.nodeValue += "", with unselected range on detachedXmlTextNode from 0 to 1 PASS detachedXmlTextNode.nodeValue += "", with selected range on detachedXmlTextNode from 0 to 1 PASS detachedXmlTextNode.nodeValue += "foo", with unselected range on detachedXmlTextNode from 0 to 1 PASS detachedXmlTextNode.nodeValue += "foo", with selected range on detachedXmlTextNode from 0 to 1 @@ -1587,9 +1587,9 @@ PASS detachedXmlTextNode.data = "", with selected range collapsed at (detachedXmlTextNode, 1) PASS detachedXmlTextNode.data = "foo", with unselected range collapsed at (detachedXmlTextNode, 1) PASS detachedXmlTextNode.data = "foo", with selected range collapsed at (detachedXmlTextNode, 1) -FAIL detachedXmlTextNode.data = detachedXmlTextNode.data, with unselected range collapsed at (detachedXmlTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlTextNode.data = detachedXmlTextNode.data, with unselected range collapsed at (detachedXmlTextNode, 1) PASS detachedXmlTextNode.data = detachedXmlTextNode.data, with selected range collapsed at (detachedXmlTextNode, 1) -FAIL detachedXmlTextNode.data += "", with unselected range collapsed at (detachedXmlTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlTextNode.data += "", with unselected range collapsed at (detachedXmlTextNode, 1) PASS detachedXmlTextNode.data += "", with selected range collapsed at (detachedXmlTextNode, 1) PASS detachedXmlTextNode.data += "foo", with unselected range collapsed at (detachedXmlTextNode, 1) PASS detachedXmlTextNode.data += "foo", with selected range collapsed at (detachedXmlTextNode, 1) @@ -1599,9 +1599,9 @@ PASS detachedXmlTextNode.textContent = "", with selected range collapsed at (detachedXmlTextNode, 1) PASS detachedXmlTextNode.textContent = "foo", with unselected range collapsed at (detachedXmlTextNode, 1) PASS detachedXmlTextNode.textContent = "foo", with selected range collapsed at (detachedXmlTextNode, 1) -FAIL detachedXmlTextNode.textContent = detachedXmlTextNode.textContent, with unselected range collapsed at (detachedXmlTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlTextNode.textContent = detachedXmlTextNode.textContent, with unselected range collapsed at (detachedXmlTextNode, 1) PASS detachedXmlTextNode.textContent = detachedXmlTextNode.textContent, with selected range collapsed at (detachedXmlTextNode, 1) -FAIL detachedXmlTextNode.textContent += "", with unselected range collapsed at (detachedXmlTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlTextNode.textContent += "", with unselected range collapsed at (detachedXmlTextNode, 1) PASS detachedXmlTextNode.textContent += "", with selected range collapsed at (detachedXmlTextNode, 1) PASS detachedXmlTextNode.textContent += "foo", with unselected range collapsed at (detachedXmlTextNode, 1) PASS detachedXmlTextNode.textContent += "foo", with selected range collapsed at (detachedXmlTextNode, 1) @@ -1611,9 +1611,9 @@ PASS detachedXmlTextNode.nodeValue = "", with selected range collapsed at (detachedXmlTextNode, 1) PASS detachedXmlTextNode.nodeValue = "foo", with unselected range collapsed at (detachedXmlTextNode, 1) PASS detachedXmlTextNode.nodeValue = "foo", with selected range collapsed at (detachedXmlTextNode, 1) -FAIL detachedXmlTextNode.nodeValue = detachedXmlTextNode.nodeValue, with unselected range collapsed at (detachedXmlTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlTextNode.nodeValue = detachedXmlTextNode.nodeValue, with unselected range collapsed at (detachedXmlTextNode, 1) PASS detachedXmlTextNode.nodeValue = detachedXmlTextNode.nodeValue, with selected range collapsed at (detachedXmlTextNode, 1) -FAIL detachedXmlTextNode.nodeValue += "", with unselected range collapsed at (detachedXmlTextNode, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlTextNode.nodeValue += "", with unselected range collapsed at (detachedXmlTextNode, 1) PASS detachedXmlTextNode.nodeValue += "", with selected range collapsed at (detachedXmlTextNode, 1) PASS detachedXmlTextNode.nodeValue += "foo", with unselected range collapsed at (detachedXmlTextNode, 1) PASS detachedXmlTextNode.nodeValue += "foo", with selected range collapsed at (detachedXmlTextNode, 1) @@ -1623,9 +1623,9 @@ PASS detachedXmlTextNode.data = "", with selected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length PASS detachedXmlTextNode.data = "foo", with unselected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length PASS detachedXmlTextNode.data = "foo", with selected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length -FAIL detachedXmlTextNode.data = detachedXmlTextNode.data, with unselected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedXmlTextNode.data = detachedXmlTextNode.data, with unselected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length PASS detachedXmlTextNode.data = detachedXmlTextNode.data, with selected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length -FAIL detachedXmlTextNode.data += "", with unselected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedXmlTextNode.data += "", with unselected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length PASS detachedXmlTextNode.data += "", with selected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length PASS detachedXmlTextNode.data += "foo", with unselected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length PASS detachedXmlTextNode.data += "foo", with selected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length @@ -1635,9 +1635,9 @@ PASS detachedXmlTextNode.textContent = "", with selected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length PASS detachedXmlTextNode.textContent = "foo", with unselected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length PASS detachedXmlTextNode.textContent = "foo", with selected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length -FAIL detachedXmlTextNode.textContent = detachedXmlTextNode.textContent, with unselected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedXmlTextNode.textContent = detachedXmlTextNode.textContent, with unselected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length PASS detachedXmlTextNode.textContent = detachedXmlTextNode.textContent, with selected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length -FAIL detachedXmlTextNode.textContent += "", with unselected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedXmlTextNode.textContent += "", with unselected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length PASS detachedXmlTextNode.textContent += "", with selected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length PASS detachedXmlTextNode.textContent += "foo", with unselected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length PASS detachedXmlTextNode.textContent += "foo", with selected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length @@ -1647,9 +1647,9 @@ PASS detachedXmlTextNode.nodeValue = "", with selected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length PASS detachedXmlTextNode.nodeValue = "foo", with unselected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length PASS detachedXmlTextNode.nodeValue = "foo", with selected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length -FAIL detachedXmlTextNode.nodeValue = detachedXmlTextNode.nodeValue, with unselected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedXmlTextNode.nodeValue = detachedXmlTextNode.nodeValue, with unselected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length PASS detachedXmlTextNode.nodeValue = detachedXmlTextNode.nodeValue, with selected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length -FAIL detachedXmlTextNode.nodeValue += "", with unselected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedXmlTextNode.nodeValue += "", with unselected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length PASS detachedXmlTextNode.nodeValue += "", with selected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length PASS detachedXmlTextNode.nodeValue += "foo", with unselected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length PASS detachedXmlTextNode.nodeValue += "foo", with selected range on detachedXmlTextNode from 0 to detachedXmlTextNode.length @@ -1659,9 +1659,9 @@ PASS detachedXmlTextNode.data = "", with selected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length PASS detachedXmlTextNode.data = "foo", with unselected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length PASS detachedXmlTextNode.data = "foo", with selected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length -FAIL detachedXmlTextNode.data = detachedXmlTextNode.data, with unselected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlTextNode.data = detachedXmlTextNode.data, with unselected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length PASS detachedXmlTextNode.data = detachedXmlTextNode.data, with selected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length -FAIL detachedXmlTextNode.data += "", with unselected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlTextNode.data += "", with unselected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length PASS detachedXmlTextNode.data += "", with selected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length PASS detachedXmlTextNode.data += "foo", with unselected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length PASS detachedXmlTextNode.data += "foo", with selected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length @@ -1671,9 +1671,9 @@ PASS detachedXmlTextNode.textContent = "", with selected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length PASS detachedXmlTextNode.textContent = "foo", with unselected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length PASS detachedXmlTextNode.textContent = "foo", with selected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length -FAIL detachedXmlTextNode.textContent = detachedXmlTextNode.textContent, with unselected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlTextNode.textContent = detachedXmlTextNode.textContent, with unselected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length PASS detachedXmlTextNode.textContent = detachedXmlTextNode.textContent, with selected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length -FAIL detachedXmlTextNode.textContent += "", with unselected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlTextNode.textContent += "", with unselected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length PASS detachedXmlTextNode.textContent += "", with selected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length PASS detachedXmlTextNode.textContent += "foo", with unselected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length PASS detachedXmlTextNode.textContent += "foo", with selected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length @@ -1683,9 +1683,9 @@ PASS detachedXmlTextNode.nodeValue = "", with selected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length PASS detachedXmlTextNode.nodeValue = "foo", with unselected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length PASS detachedXmlTextNode.nodeValue = "foo", with selected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length -FAIL detachedXmlTextNode.nodeValue = detachedXmlTextNode.nodeValue, with unselected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlTextNode.nodeValue = detachedXmlTextNode.nodeValue, with unselected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length PASS detachedXmlTextNode.nodeValue = detachedXmlTextNode.nodeValue, with selected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length -FAIL detachedXmlTextNode.nodeValue += "", with unselected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlTextNode.nodeValue += "", with unselected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length PASS detachedXmlTextNode.nodeValue += "", with selected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length PASS detachedXmlTextNode.nodeValue += "foo", with unselected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length PASS detachedXmlTextNode.nodeValue += "foo", with selected range on detachedXmlTextNode from 1 to detachedXmlTextNode.length @@ -1695,9 +1695,9 @@ PASS detachedXmlTextNode.data = "", with selected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) PASS detachedXmlTextNode.data = "foo", with unselected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) PASS detachedXmlTextNode.data = "foo", with selected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) -FAIL detachedXmlTextNode.data = detachedXmlTextNode.data, with unselected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedXmlTextNode.data = detachedXmlTextNode.data, with unselected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) PASS detachedXmlTextNode.data = detachedXmlTextNode.data, with selected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) -FAIL detachedXmlTextNode.data += "", with unselected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedXmlTextNode.data += "", with unselected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) PASS detachedXmlTextNode.data += "", with selected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) PASS detachedXmlTextNode.data += "foo", with unselected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) PASS detachedXmlTextNode.data += "foo", with selected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) @@ -1707,9 +1707,9 @@ PASS detachedXmlTextNode.textContent = "", with selected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) PASS detachedXmlTextNode.textContent = "foo", with unselected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) PASS detachedXmlTextNode.textContent = "foo", with selected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) -FAIL detachedXmlTextNode.textContent = detachedXmlTextNode.textContent, with unselected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedXmlTextNode.textContent = detachedXmlTextNode.textContent, with unselected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) PASS detachedXmlTextNode.textContent = detachedXmlTextNode.textContent, with selected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) -FAIL detachedXmlTextNode.textContent += "", with unselected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedXmlTextNode.textContent += "", with unselected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) PASS detachedXmlTextNode.textContent += "", with selected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) PASS detachedXmlTextNode.textContent += "foo", with unselected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) PASS detachedXmlTextNode.textContent += "foo", with selected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) @@ -1719,9 +1719,9 @@ PASS detachedXmlTextNode.nodeValue = "", with selected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) PASS detachedXmlTextNode.nodeValue = "foo", with unselected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) PASS detachedXmlTextNode.nodeValue = "foo", with selected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) -FAIL detachedXmlTextNode.nodeValue = detachedXmlTextNode.nodeValue, with unselected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedXmlTextNode.nodeValue = detachedXmlTextNode.nodeValue, with unselected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) PASS detachedXmlTextNode.nodeValue = detachedXmlTextNode.nodeValue, with selected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) -FAIL detachedXmlTextNode.nodeValue += "", with unselected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedXmlTextNode.nodeValue += "", with unselected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) PASS detachedXmlTextNode.nodeValue += "", with selected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) PASS detachedXmlTextNode.nodeValue += "foo", with unselected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) PASS detachedXmlTextNode.nodeValue += "foo", with selected range collapsed at (detachedXmlTextNode, detachedXmlTextNode.length) @@ -1767,9 +1767,9 @@ PASS comment.data = "", with selected range on comment from 0 to 1 PASS comment.data = "foo", with unselected range on comment from 0 to 1 PASS comment.data = "foo", with selected range on comment from 0 to 1 -FAIL comment.data = comment.data, with unselected range on comment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS comment.data = comment.data, with unselected range on comment from 0 to 1 PASS comment.data = comment.data, with selected range on comment from 0 to 1 -FAIL comment.data += "", with unselected range on comment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS comment.data += "", with unselected range on comment from 0 to 1 PASS comment.data += "", with selected range on comment from 0 to 1 PASS comment.data += "foo", with unselected range on comment from 0 to 1 PASS comment.data += "foo", with selected range on comment from 0 to 1 @@ -1779,9 +1779,9 @@ PASS comment.textContent = "", with selected range on comment from 0 to 1 PASS comment.textContent = "foo", with unselected range on comment from 0 to 1 PASS comment.textContent = "foo", with selected range on comment from 0 to 1 -FAIL comment.textContent = comment.textContent, with unselected range on comment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS comment.textContent = comment.textContent, with unselected range on comment from 0 to 1 PASS comment.textContent = comment.textContent, with selected range on comment from 0 to 1 -FAIL comment.textContent += "", with unselected range on comment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS comment.textContent += "", with unselected range on comment from 0 to 1 PASS comment.textContent += "", with selected range on comment from 0 to 1 PASS comment.textContent += "foo", with unselected range on comment from 0 to 1 PASS comment.textContent += "foo", with selected range on comment from 0 to 1 @@ -1791,9 +1791,9 @@ PASS comment.nodeValue = "", with selected range on comment from 0 to 1 PASS comment.nodeValue = "foo", with unselected range on comment from 0 to 1 PASS comment.nodeValue = "foo", with selected range on comment from 0 to 1 -FAIL comment.nodeValue = comment.nodeValue, with unselected range on comment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS comment.nodeValue = comment.nodeValue, with unselected range on comment from 0 to 1 PASS comment.nodeValue = comment.nodeValue, with selected range on comment from 0 to 1 -FAIL comment.nodeValue += "", with unselected range on comment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS comment.nodeValue += "", with unselected range on comment from 0 to 1 PASS comment.nodeValue += "", with selected range on comment from 0 to 1 PASS comment.nodeValue += "foo", with unselected range on comment from 0 to 1 PASS comment.nodeValue += "foo", with selected range on comment from 0 to 1 @@ -1803,9 +1803,9 @@ PASS comment.data = "", with selected range collapsed at (comment, 1) PASS comment.data = "foo", with unselected range collapsed at (comment, 1) PASS comment.data = "foo", with selected range collapsed at (comment, 1) -FAIL comment.data = comment.data, with unselected range collapsed at (comment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS comment.data = comment.data, with unselected range collapsed at (comment, 1) PASS comment.data = comment.data, with selected range collapsed at (comment, 1) -FAIL comment.data += "", with unselected range collapsed at (comment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS comment.data += "", with unselected range collapsed at (comment, 1) PASS comment.data += "", with selected range collapsed at (comment, 1) PASS comment.data += "foo", with unselected range collapsed at (comment, 1) PASS comment.data += "foo", with selected range collapsed at (comment, 1) @@ -1815,9 +1815,9 @@ PASS comment.textContent = "", with selected range collapsed at (comment, 1) PASS comment.textContent = "foo", with unselected range collapsed at (comment, 1) PASS comment.textContent = "foo", with selected range collapsed at (comment, 1) -FAIL comment.textContent = comment.textContent, with unselected range collapsed at (comment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS comment.textContent = comment.textContent, with unselected range collapsed at (comment, 1) PASS comment.textContent = comment.textContent, with selected range collapsed at (comment, 1) -FAIL comment.textContent += "", with unselected range collapsed at (comment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS comment.textContent += "", with unselected range collapsed at (comment, 1) PASS comment.textContent += "", with selected range collapsed at (comment, 1) PASS comment.textContent += "foo", with unselected range collapsed at (comment, 1) PASS comment.textContent += "foo", with selected range collapsed at (comment, 1) @@ -1827,9 +1827,9 @@ PASS comment.nodeValue = "", with selected range collapsed at (comment, 1) PASS comment.nodeValue = "foo", with unselected range collapsed at (comment, 1) PASS comment.nodeValue = "foo", with selected range collapsed at (comment, 1) -FAIL comment.nodeValue = comment.nodeValue, with unselected range collapsed at (comment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS comment.nodeValue = comment.nodeValue, with unselected range collapsed at (comment, 1) PASS comment.nodeValue = comment.nodeValue, with selected range collapsed at (comment, 1) -FAIL comment.nodeValue += "", with unselected range collapsed at (comment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS comment.nodeValue += "", with unselected range collapsed at (comment, 1) PASS comment.nodeValue += "", with selected range collapsed at (comment, 1) PASS comment.nodeValue += "foo", with unselected range collapsed at (comment, 1) PASS comment.nodeValue += "foo", with selected range collapsed at (comment, 1) @@ -1839,9 +1839,9 @@ PASS comment.data = "", with selected range on comment from 0 to comment.length PASS comment.data = "foo", with unselected range on comment from 0 to comment.length PASS comment.data = "foo", with selected range on comment from 0 to comment.length -FAIL comment.data = comment.data, with unselected range on comment from 0 to comment.length assert_equals: Wrong end offset expected 0 but got 14 +PASS comment.data = comment.data, with unselected range on comment from 0 to comment.length PASS comment.data = comment.data, with selected range on comment from 0 to comment.length -FAIL comment.data += "", with unselected range on comment from 0 to comment.length assert_equals: Wrong end offset expected 0 but got 14 +PASS comment.data += "", with unselected range on comment from 0 to comment.length PASS comment.data += "", with selected range on comment from 0 to comment.length PASS comment.data += "foo", with unselected range on comment from 0 to comment.length PASS comment.data += "foo", with selected range on comment from 0 to comment.length @@ -1851,9 +1851,9 @@ PASS comment.textContent = "", with selected range on comment from 0 to comment.length PASS comment.textContent = "foo", with unselected range on comment from 0 to comment.length PASS comment.textContent = "foo", with selected range on comment from 0 to comment.length -FAIL comment.textContent = comment.textContent, with unselected range on comment from 0 to comment.length assert_equals: Wrong end offset expected 0 but got 14 +PASS comment.textContent = comment.textContent, with unselected range on comment from 0 to comment.length PASS comment.textContent = comment.textContent, with selected range on comment from 0 to comment.length -FAIL comment.textContent += "", with unselected range on comment from 0 to comment.length assert_equals: Wrong end offset expected 0 but got 14 +PASS comment.textContent += "", with unselected range on comment from 0 to comment.length PASS comment.textContent += "", with selected range on comment from 0 to comment.length PASS comment.textContent += "foo", with unselected range on comment from 0 to comment.length PASS comment.textContent += "foo", with selected range on comment from 0 to comment.length @@ -1863,9 +1863,9 @@ PASS comment.nodeValue = "", with selected range on comment from 0 to comment.length PASS comment.nodeValue = "foo", with unselected range on comment from 0 to comment.length PASS comment.nodeValue = "foo", with selected range on comment from 0 to comment.length -FAIL comment.nodeValue = comment.nodeValue, with unselected range on comment from 0 to comment.length assert_equals: Wrong end offset expected 0 but got 14 +PASS comment.nodeValue = comment.nodeValue, with unselected range on comment from 0 to comment.length PASS comment.nodeValue = comment.nodeValue, with selected range on comment from 0 to comment.length -FAIL comment.nodeValue += "", with unselected range on comment from 0 to comment.length assert_equals: Wrong end offset expected 0 but got 14 +PASS comment.nodeValue += "", with unselected range on comment from 0 to comment.length PASS comment.nodeValue += "", with selected range on comment from 0 to comment.length PASS comment.nodeValue += "foo", with unselected range on comment from 0 to comment.length PASS comment.nodeValue += "foo", with selected range on comment from 0 to comment.length @@ -1875,9 +1875,9 @@ PASS comment.data = "", with selected range on comment from 1 to comment.length PASS comment.data = "foo", with unselected range on comment from 1 to comment.length PASS comment.data = "foo", with selected range on comment from 1 to comment.length -FAIL comment.data = comment.data, with unselected range on comment from 1 to comment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS comment.data = comment.data, with unselected range on comment from 1 to comment.length PASS comment.data = comment.data, with selected range on comment from 1 to comment.length -FAIL comment.data += "", with unselected range on comment from 1 to comment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS comment.data += "", with unselected range on comment from 1 to comment.length PASS comment.data += "", with selected range on comment from 1 to comment.length PASS comment.data += "foo", with unselected range on comment from 1 to comment.length PASS comment.data += "foo", with selected range on comment from 1 to comment.length @@ -1887,9 +1887,9 @@ PASS comment.textContent = "", with selected range on comment from 1 to comment.length PASS comment.textContent = "foo", with unselected range on comment from 1 to comment.length PASS comment.textContent = "foo", with selected range on comment from 1 to comment.length -FAIL comment.textContent = comment.textContent, with unselected range on comment from 1 to comment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS comment.textContent = comment.textContent, with unselected range on comment from 1 to comment.length PASS comment.textContent = comment.textContent, with selected range on comment from 1 to comment.length -FAIL comment.textContent += "", with unselected range on comment from 1 to comment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS comment.textContent += "", with unselected range on comment from 1 to comment.length PASS comment.textContent += "", with selected range on comment from 1 to comment.length PASS comment.textContent += "foo", with unselected range on comment from 1 to comment.length PASS comment.textContent += "foo", with selected range on comment from 1 to comment.length @@ -1899,9 +1899,9 @@ PASS comment.nodeValue = "", with selected range on comment from 1 to comment.length PASS comment.nodeValue = "foo", with unselected range on comment from 1 to comment.length PASS comment.nodeValue = "foo", with selected range on comment from 1 to comment.length -FAIL comment.nodeValue = comment.nodeValue, with unselected range on comment from 1 to comment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS comment.nodeValue = comment.nodeValue, with unselected range on comment from 1 to comment.length PASS comment.nodeValue = comment.nodeValue, with selected range on comment from 1 to comment.length -FAIL comment.nodeValue += "", with unselected range on comment from 1 to comment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS comment.nodeValue += "", with unselected range on comment from 1 to comment.length PASS comment.nodeValue += "", with selected range on comment from 1 to comment.length PASS comment.nodeValue += "foo", with unselected range on comment from 1 to comment.length PASS comment.nodeValue += "foo", with selected range on comment from 1 to comment.length @@ -1911,9 +1911,9 @@ PASS comment.data = "", with selected range collapsed at (comment, comment.length) PASS comment.data = "foo", with unselected range collapsed at (comment, comment.length) PASS comment.data = "foo", with selected range collapsed at (comment, comment.length) -FAIL comment.data = comment.data, with unselected range collapsed at (comment, comment.length) assert_equals: Wrong start offset expected 0 but got 14 +PASS comment.data = comment.data, with unselected range collapsed at (comment, comment.length) PASS comment.data = comment.data, with selected range collapsed at (comment, comment.length) -FAIL comment.data += "", with unselected range collapsed at (comment, comment.length) assert_equals: Wrong start offset expected 0 but got 14 +PASS comment.data += "", with unselected range collapsed at (comment, comment.length) PASS comment.data += "", with selected range collapsed at (comment, comment.length) PASS comment.data += "foo", with unselected range collapsed at (comment, comment.length) PASS comment.data += "foo", with selected range collapsed at (comment, comment.length) @@ -1923,9 +1923,9 @@ PASS comment.textContent = "", with selected range collapsed at (comment, comment.length) PASS comment.textContent = "foo", with unselected range collapsed at (comment, comment.length) PASS comment.textContent = "foo", with selected range collapsed at (comment, comment.length) -FAIL comment.textContent = comment.textContent, with unselected range collapsed at (comment, comment.length) assert_equals: Wrong start offset expected 0 but got 14 +PASS comment.textContent = comment.textContent, with unselected range collapsed at (comment, comment.length) PASS comment.textContent = comment.textContent, with selected range collapsed at (comment, comment.length) -FAIL comment.textContent += "", with unselected range collapsed at (comment, comment.length) assert_equals: Wrong start offset expected 0 but got 14 +PASS comment.textContent += "", with unselected range collapsed at (comment, comment.length) PASS comment.textContent += "", with selected range collapsed at (comment, comment.length) PASS comment.textContent += "foo", with unselected range collapsed at (comment, comment.length) PASS comment.textContent += "foo", with selected range collapsed at (comment, comment.length) @@ -1935,9 +1935,9 @@ PASS comment.nodeValue = "", with selected range collapsed at (comment, comment.length) PASS comment.nodeValue = "foo", with unselected range collapsed at (comment, comment.length) PASS comment.nodeValue = "foo", with selected range collapsed at (comment, comment.length) -FAIL comment.nodeValue = comment.nodeValue, with unselected range collapsed at (comment, comment.length) assert_equals: Wrong start offset expected 0 but got 14 +PASS comment.nodeValue = comment.nodeValue, with unselected range collapsed at (comment, comment.length) PASS comment.nodeValue = comment.nodeValue, with selected range collapsed at (comment, comment.length) -FAIL comment.nodeValue += "", with unselected range collapsed at (comment, comment.length) assert_equals: Wrong start offset expected 0 but got 14 +PASS comment.nodeValue += "", with unselected range collapsed at (comment, comment.length) PASS comment.nodeValue += "", with selected range collapsed at (comment, comment.length) PASS comment.nodeValue += "foo", with unselected range collapsed at (comment, comment.length) PASS comment.nodeValue += "foo", with selected range collapsed at (comment, comment.length) @@ -1983,9 +1983,9 @@ PASS foreignComment.data = "", with selected range on foreignComment from 0 to 1 PASS foreignComment.data = "foo", with unselected range on foreignComment from 0 to 1 PASS foreignComment.data = "foo", with selected range on foreignComment from 0 to 1 -FAIL foreignComment.data = foreignComment.data, with unselected range on foreignComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS foreignComment.data = foreignComment.data, with unselected range on foreignComment from 0 to 1 PASS foreignComment.data = foreignComment.data, with selected range on foreignComment from 0 to 1 -FAIL foreignComment.data += "", with unselected range on foreignComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS foreignComment.data += "", with unselected range on foreignComment from 0 to 1 PASS foreignComment.data += "", with selected range on foreignComment from 0 to 1 PASS foreignComment.data += "foo", with unselected range on foreignComment from 0 to 1 PASS foreignComment.data += "foo", with selected range on foreignComment from 0 to 1 @@ -1995,9 +1995,9 @@ PASS foreignComment.textContent = "", with selected range on foreignComment from 0 to 1 PASS foreignComment.textContent = "foo", with unselected range on foreignComment from 0 to 1 PASS foreignComment.textContent = "foo", with selected range on foreignComment from 0 to 1 -FAIL foreignComment.textContent = foreignComment.textContent, with unselected range on foreignComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS foreignComment.textContent = foreignComment.textContent, with unselected range on foreignComment from 0 to 1 PASS foreignComment.textContent = foreignComment.textContent, with selected range on foreignComment from 0 to 1 -FAIL foreignComment.textContent += "", with unselected range on foreignComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS foreignComment.textContent += "", with unselected range on foreignComment from 0 to 1 PASS foreignComment.textContent += "", with selected range on foreignComment from 0 to 1 PASS foreignComment.textContent += "foo", with unselected range on foreignComment from 0 to 1 PASS foreignComment.textContent += "foo", with selected range on foreignComment from 0 to 1 @@ -2007,9 +2007,9 @@ PASS foreignComment.nodeValue = "", with selected range on foreignComment from 0 to 1 PASS foreignComment.nodeValue = "foo", with unselected range on foreignComment from 0 to 1 PASS foreignComment.nodeValue = "foo", with selected range on foreignComment from 0 to 1 -FAIL foreignComment.nodeValue = foreignComment.nodeValue, with unselected range on foreignComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS foreignComment.nodeValue = foreignComment.nodeValue, with unselected range on foreignComment from 0 to 1 PASS foreignComment.nodeValue = foreignComment.nodeValue, with selected range on foreignComment from 0 to 1 -FAIL foreignComment.nodeValue += "", with unselected range on foreignComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS foreignComment.nodeValue += "", with unselected range on foreignComment from 0 to 1 PASS foreignComment.nodeValue += "", with selected range on foreignComment from 0 to 1 PASS foreignComment.nodeValue += "foo", with unselected range on foreignComment from 0 to 1 PASS foreignComment.nodeValue += "foo", with selected range on foreignComment from 0 to 1 @@ -2019,9 +2019,9 @@ PASS foreignComment.data = "", with selected range collapsed at (foreignComment, 1) PASS foreignComment.data = "foo", with unselected range collapsed at (foreignComment, 1) PASS foreignComment.data = "foo", with selected range collapsed at (foreignComment, 1) -FAIL foreignComment.data = foreignComment.data, with unselected range collapsed at (foreignComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignComment.data = foreignComment.data, with unselected range collapsed at (foreignComment, 1) PASS foreignComment.data = foreignComment.data, with selected range collapsed at (foreignComment, 1) -FAIL foreignComment.data += "", with unselected range collapsed at (foreignComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignComment.data += "", with unselected range collapsed at (foreignComment, 1) PASS foreignComment.data += "", with selected range collapsed at (foreignComment, 1) PASS foreignComment.data += "foo", with unselected range collapsed at (foreignComment, 1) PASS foreignComment.data += "foo", with selected range collapsed at (foreignComment, 1) @@ -2031,9 +2031,9 @@ PASS foreignComment.textContent = "", with selected range collapsed at (foreignComment, 1) PASS foreignComment.textContent = "foo", with unselected range collapsed at (foreignComment, 1) PASS foreignComment.textContent = "foo", with selected range collapsed at (foreignComment, 1) -FAIL foreignComment.textContent = foreignComment.textContent, with unselected range collapsed at (foreignComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignComment.textContent = foreignComment.textContent, with unselected range collapsed at (foreignComment, 1) PASS foreignComment.textContent = foreignComment.textContent, with selected range collapsed at (foreignComment, 1) -FAIL foreignComment.textContent += "", with unselected range collapsed at (foreignComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignComment.textContent += "", with unselected range collapsed at (foreignComment, 1) PASS foreignComment.textContent += "", with selected range collapsed at (foreignComment, 1) PASS foreignComment.textContent += "foo", with unselected range collapsed at (foreignComment, 1) PASS foreignComment.textContent += "foo", with selected range collapsed at (foreignComment, 1) @@ -2043,9 +2043,9 @@ PASS foreignComment.nodeValue = "", with selected range collapsed at (foreignComment, 1) PASS foreignComment.nodeValue = "foo", with unselected range collapsed at (foreignComment, 1) PASS foreignComment.nodeValue = "foo", with selected range collapsed at (foreignComment, 1) -FAIL foreignComment.nodeValue = foreignComment.nodeValue, with unselected range collapsed at (foreignComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignComment.nodeValue = foreignComment.nodeValue, with unselected range collapsed at (foreignComment, 1) PASS foreignComment.nodeValue = foreignComment.nodeValue, with selected range collapsed at (foreignComment, 1) -FAIL foreignComment.nodeValue += "", with unselected range collapsed at (foreignComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignComment.nodeValue += "", with unselected range collapsed at (foreignComment, 1) PASS foreignComment.nodeValue += "", with selected range collapsed at (foreignComment, 1) PASS foreignComment.nodeValue += "foo", with unselected range collapsed at (foreignComment, 1) PASS foreignComment.nodeValue += "foo", with selected range collapsed at (foreignComment, 1) @@ -2055,9 +2055,9 @@ PASS foreignComment.data = "", with selected range on foreignComment from 0 to foreignComment.length PASS foreignComment.data = "foo", with unselected range on foreignComment from 0 to foreignComment.length PASS foreignComment.data = "foo", with selected range on foreignComment from 0 to foreignComment.length -FAIL foreignComment.data = foreignComment.data, with unselected range on foreignComment from 0 to foreignComment.length assert_equals: Wrong end offset expected 0 but got 100 +PASS foreignComment.data = foreignComment.data, with unselected range on foreignComment from 0 to foreignComment.length PASS foreignComment.data = foreignComment.data, with selected range on foreignComment from 0 to foreignComment.length -FAIL foreignComment.data += "", with unselected range on foreignComment from 0 to foreignComment.length assert_equals: Wrong end offset expected 0 but got 100 +PASS foreignComment.data += "", with unselected range on foreignComment from 0 to foreignComment.length PASS foreignComment.data += "", with selected range on foreignComment from 0 to foreignComment.length PASS foreignComment.data += "foo", with unselected range on foreignComment from 0 to foreignComment.length PASS foreignComment.data += "foo", with selected range on foreignComment from 0 to foreignComment.length @@ -2067,9 +2067,9 @@ PASS foreignComment.textContent = "", with selected range on foreignComment from 0 to foreignComment.length PASS foreignComment.textContent = "foo", with unselected range on foreignComment from 0 to foreignComment.length PASS foreignComment.textContent = "foo", with selected range on foreignComment from 0 to foreignComment.length -FAIL foreignComment.textContent = foreignComment.textContent, with unselected range on foreignComment from 0 to foreignComment.length assert_equals: Wrong end offset expected 0 but got 100 +PASS foreignComment.textContent = foreignComment.textContent, with unselected range on foreignComment from 0 to foreignComment.length PASS foreignComment.textContent = foreignComment.textContent, with selected range on foreignComment from 0 to foreignComment.length -FAIL foreignComment.textContent += "", with unselected range on foreignComment from 0 to foreignComment.length assert_equals: Wrong end offset expected 0 but got 100 +PASS foreignComment.textContent += "", with unselected range on foreignComment from 0 to foreignComment.length PASS foreignComment.textContent += "", with selected range on foreignComment from 0 to foreignComment.length PASS foreignComment.textContent += "foo", with unselected range on foreignComment from 0 to foreignComment.length PASS foreignComment.textContent += "foo", with selected range on foreignComment from 0 to foreignComment.length @@ -2079,9 +2079,9 @@ PASS foreignComment.nodeValue = "", with selected range on foreignComment from 0 to foreignComment.length PASS foreignComment.nodeValue = "foo", with unselected range on foreignComment from 0 to foreignComment.length PASS foreignComment.nodeValue = "foo", with selected range on foreignComment from 0 to foreignComment.length -FAIL foreignComment.nodeValue = foreignComment.nodeValue, with unselected range on foreignComment from 0 to foreignComment.length assert_equals: Wrong end offset expected 0 but got 100 +PASS foreignComment.nodeValue = foreignComment.nodeValue, with unselected range on foreignComment from 0 to foreignComment.length PASS foreignComment.nodeValue = foreignComment.nodeValue, with selected range on foreignComment from 0 to foreignComment.length -FAIL foreignComment.nodeValue += "", with unselected range on foreignComment from 0 to foreignComment.length assert_equals: Wrong end offset expected 0 but got 100 +PASS foreignComment.nodeValue += "", with unselected range on foreignComment from 0 to foreignComment.length PASS foreignComment.nodeValue += "", with selected range on foreignComment from 0 to foreignComment.length PASS foreignComment.nodeValue += "foo", with unselected range on foreignComment from 0 to foreignComment.length PASS foreignComment.nodeValue += "foo", with selected range on foreignComment from 0 to foreignComment.length @@ -2091,9 +2091,9 @@ PASS foreignComment.data = "", with selected range on foreignComment from 1 to foreignComment.length PASS foreignComment.data = "foo", with unselected range on foreignComment from 1 to foreignComment.length PASS foreignComment.data = "foo", with selected range on foreignComment from 1 to foreignComment.length -FAIL foreignComment.data = foreignComment.data, with unselected range on foreignComment from 1 to foreignComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignComment.data = foreignComment.data, with unselected range on foreignComment from 1 to foreignComment.length PASS foreignComment.data = foreignComment.data, with selected range on foreignComment from 1 to foreignComment.length -FAIL foreignComment.data += "", with unselected range on foreignComment from 1 to foreignComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignComment.data += "", with unselected range on foreignComment from 1 to foreignComment.length PASS foreignComment.data += "", with selected range on foreignComment from 1 to foreignComment.length PASS foreignComment.data += "foo", with unselected range on foreignComment from 1 to foreignComment.length PASS foreignComment.data += "foo", with selected range on foreignComment from 1 to foreignComment.length @@ -2103,9 +2103,9 @@ PASS foreignComment.textContent = "", with selected range on foreignComment from 1 to foreignComment.length PASS foreignComment.textContent = "foo", with unselected range on foreignComment from 1 to foreignComment.length PASS foreignComment.textContent = "foo", with selected range on foreignComment from 1 to foreignComment.length -FAIL foreignComment.textContent = foreignComment.textContent, with unselected range on foreignComment from 1 to foreignComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignComment.textContent = foreignComment.textContent, with unselected range on foreignComment from 1 to foreignComment.length PASS foreignComment.textContent = foreignComment.textContent, with selected range on foreignComment from 1 to foreignComment.length -FAIL foreignComment.textContent += "", with unselected range on foreignComment from 1 to foreignComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignComment.textContent += "", with unselected range on foreignComment from 1 to foreignComment.length PASS foreignComment.textContent += "", with selected range on foreignComment from 1 to foreignComment.length PASS foreignComment.textContent += "foo", with unselected range on foreignComment from 1 to foreignComment.length PASS foreignComment.textContent += "foo", with selected range on foreignComment from 1 to foreignComment.length @@ -2115,9 +2115,9 @@ PASS foreignComment.nodeValue = "", with selected range on foreignComment from 1 to foreignComment.length PASS foreignComment.nodeValue = "foo", with unselected range on foreignComment from 1 to foreignComment.length PASS foreignComment.nodeValue = "foo", with selected range on foreignComment from 1 to foreignComment.length -FAIL foreignComment.nodeValue = foreignComment.nodeValue, with unselected range on foreignComment from 1 to foreignComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignComment.nodeValue = foreignComment.nodeValue, with unselected range on foreignComment from 1 to foreignComment.length PASS foreignComment.nodeValue = foreignComment.nodeValue, with selected range on foreignComment from 1 to foreignComment.length -FAIL foreignComment.nodeValue += "", with unselected range on foreignComment from 1 to foreignComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS foreignComment.nodeValue += "", with unselected range on foreignComment from 1 to foreignComment.length PASS foreignComment.nodeValue += "", with selected range on foreignComment from 1 to foreignComment.length PASS foreignComment.nodeValue += "foo", with unselected range on foreignComment from 1 to foreignComment.length PASS foreignComment.nodeValue += "foo", with selected range on foreignComment from 1 to foreignComment.length @@ -2127,9 +2127,9 @@ PASS foreignComment.data = "", with selected range collapsed at (foreignComment, foreignComment.length) PASS foreignComment.data = "foo", with unselected range collapsed at (foreignComment, foreignComment.length) PASS foreignComment.data = "foo", with selected range collapsed at (foreignComment, foreignComment.length) -FAIL foreignComment.data = foreignComment.data, with unselected range collapsed at (foreignComment, foreignComment.length) assert_equals: Wrong start offset expected 0 but got 100 +PASS foreignComment.data = foreignComment.data, with unselected range collapsed at (foreignComment, foreignComment.length) PASS foreignComment.data = foreignComment.data, with selected range collapsed at (foreignComment, foreignComment.length) -FAIL foreignComment.data += "", with unselected range collapsed at (foreignComment, foreignComment.length) assert_equals: Wrong start offset expected 0 but got 100 +PASS foreignComment.data += "", with unselected range collapsed at (foreignComment, foreignComment.length) PASS foreignComment.data += "", with selected range collapsed at (foreignComment, foreignComment.length) PASS foreignComment.data += "foo", with unselected range collapsed at (foreignComment, foreignComment.length) PASS foreignComment.data += "foo", with selected range collapsed at (foreignComment, foreignComment.length) @@ -2139,9 +2139,9 @@ PASS foreignComment.textContent = "", with selected range collapsed at (foreignComment, foreignComment.length) PASS foreignComment.textContent = "foo", with unselected range collapsed at (foreignComment, foreignComment.length) PASS foreignComment.textContent = "foo", with selected range collapsed at (foreignComment, foreignComment.length) -FAIL foreignComment.textContent = foreignComment.textContent, with unselected range collapsed at (foreignComment, foreignComment.length) assert_equals: Wrong start offset expected 0 but got 100 +PASS foreignComment.textContent = foreignComment.textContent, with unselected range collapsed at (foreignComment, foreignComment.length) PASS foreignComment.textContent = foreignComment.textContent, with selected range collapsed at (foreignComment, foreignComment.length) -FAIL foreignComment.textContent += "", with unselected range collapsed at (foreignComment, foreignComment.length) assert_equals: Wrong start offset expected 0 but got 100 +PASS foreignComment.textContent += "", with unselected range collapsed at (foreignComment, foreignComment.length) PASS foreignComment.textContent += "", with selected range collapsed at (foreignComment, foreignComment.length) PASS foreignComment.textContent += "foo", with unselected range collapsed at (foreignComment, foreignComment.length) PASS foreignComment.textContent += "foo", with selected range collapsed at (foreignComment, foreignComment.length) @@ -2151,9 +2151,9 @@ PASS foreignComment.nodeValue = "", with selected range collapsed at (foreignComment, foreignComment.length) PASS foreignComment.nodeValue = "foo", with unselected range collapsed at (foreignComment, foreignComment.length) PASS foreignComment.nodeValue = "foo", with selected range collapsed at (foreignComment, foreignComment.length) -FAIL foreignComment.nodeValue = foreignComment.nodeValue, with unselected range collapsed at (foreignComment, foreignComment.length) assert_equals: Wrong start offset expected 0 but got 100 +PASS foreignComment.nodeValue = foreignComment.nodeValue, with unselected range collapsed at (foreignComment, foreignComment.length) PASS foreignComment.nodeValue = foreignComment.nodeValue, with selected range collapsed at (foreignComment, foreignComment.length) -FAIL foreignComment.nodeValue += "", with unselected range collapsed at (foreignComment, foreignComment.length) assert_equals: Wrong start offset expected 0 but got 100 +PASS foreignComment.nodeValue += "", with unselected range collapsed at (foreignComment, foreignComment.length) PASS foreignComment.nodeValue += "", with selected range collapsed at (foreignComment, foreignComment.length) PASS foreignComment.nodeValue += "foo", with unselected range collapsed at (foreignComment, foreignComment.length) PASS foreignComment.nodeValue += "foo", with selected range collapsed at (foreignComment, foreignComment.length) @@ -2199,9 +2199,9 @@ PASS xmlComment.data = "", with selected range on xmlComment from 0 to 1 PASS xmlComment.data = "foo", with unselected range on xmlComment from 0 to 1 PASS xmlComment.data = "foo", with selected range on xmlComment from 0 to 1 -FAIL xmlComment.data = xmlComment.data, with unselected range on xmlComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS xmlComment.data = xmlComment.data, with unselected range on xmlComment from 0 to 1 PASS xmlComment.data = xmlComment.data, with selected range on xmlComment from 0 to 1 -FAIL xmlComment.data += "", with unselected range on xmlComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS xmlComment.data += "", with unselected range on xmlComment from 0 to 1 PASS xmlComment.data += "", with selected range on xmlComment from 0 to 1 PASS xmlComment.data += "foo", with unselected range on xmlComment from 0 to 1 PASS xmlComment.data += "foo", with selected range on xmlComment from 0 to 1 @@ -2211,9 +2211,9 @@ PASS xmlComment.textContent = "", with selected range on xmlComment from 0 to 1 PASS xmlComment.textContent = "foo", with unselected range on xmlComment from 0 to 1 PASS xmlComment.textContent = "foo", with selected range on xmlComment from 0 to 1 -FAIL xmlComment.textContent = xmlComment.textContent, with unselected range on xmlComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS xmlComment.textContent = xmlComment.textContent, with unselected range on xmlComment from 0 to 1 PASS xmlComment.textContent = xmlComment.textContent, with selected range on xmlComment from 0 to 1 -FAIL xmlComment.textContent += "", with unselected range on xmlComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS xmlComment.textContent += "", with unselected range on xmlComment from 0 to 1 PASS xmlComment.textContent += "", with selected range on xmlComment from 0 to 1 PASS xmlComment.textContent += "foo", with unselected range on xmlComment from 0 to 1 PASS xmlComment.textContent += "foo", with selected range on xmlComment from 0 to 1 @@ -2223,9 +2223,9 @@ PASS xmlComment.nodeValue = "", with selected range on xmlComment from 0 to 1 PASS xmlComment.nodeValue = "foo", with unselected range on xmlComment from 0 to 1 PASS xmlComment.nodeValue = "foo", with selected range on xmlComment from 0 to 1 -FAIL xmlComment.nodeValue = xmlComment.nodeValue, with unselected range on xmlComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS xmlComment.nodeValue = xmlComment.nodeValue, with unselected range on xmlComment from 0 to 1 PASS xmlComment.nodeValue = xmlComment.nodeValue, with selected range on xmlComment from 0 to 1 -FAIL xmlComment.nodeValue += "", with unselected range on xmlComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS xmlComment.nodeValue += "", with unselected range on xmlComment from 0 to 1 PASS xmlComment.nodeValue += "", with selected range on xmlComment from 0 to 1 PASS xmlComment.nodeValue += "foo", with unselected range on xmlComment from 0 to 1 PASS xmlComment.nodeValue += "foo", with selected range on xmlComment from 0 to 1 @@ -2235,9 +2235,9 @@ PASS xmlComment.data = "", with selected range collapsed at (xmlComment, 1) PASS xmlComment.data = "foo", with unselected range collapsed at (xmlComment, 1) PASS xmlComment.data = "foo", with selected range collapsed at (xmlComment, 1) -FAIL xmlComment.data = xmlComment.data, with unselected range collapsed at (xmlComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlComment.data = xmlComment.data, with unselected range collapsed at (xmlComment, 1) PASS xmlComment.data = xmlComment.data, with selected range collapsed at (xmlComment, 1) -FAIL xmlComment.data += "", with unselected range collapsed at (xmlComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlComment.data += "", with unselected range collapsed at (xmlComment, 1) PASS xmlComment.data += "", with selected range collapsed at (xmlComment, 1) PASS xmlComment.data += "foo", with unselected range collapsed at (xmlComment, 1) PASS xmlComment.data += "foo", with selected range collapsed at (xmlComment, 1) @@ -2247,9 +2247,9 @@ PASS xmlComment.textContent = "", with selected range collapsed at (xmlComment, 1) PASS xmlComment.textContent = "foo", with unselected range collapsed at (xmlComment, 1) PASS xmlComment.textContent = "foo", with selected range collapsed at (xmlComment, 1) -FAIL xmlComment.textContent = xmlComment.textContent, with unselected range collapsed at (xmlComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlComment.textContent = xmlComment.textContent, with unselected range collapsed at (xmlComment, 1) PASS xmlComment.textContent = xmlComment.textContent, with selected range collapsed at (xmlComment, 1) -FAIL xmlComment.textContent += "", with unselected range collapsed at (xmlComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlComment.textContent += "", with unselected range collapsed at (xmlComment, 1) PASS xmlComment.textContent += "", with selected range collapsed at (xmlComment, 1) PASS xmlComment.textContent += "foo", with unselected range collapsed at (xmlComment, 1) PASS xmlComment.textContent += "foo", with selected range collapsed at (xmlComment, 1) @@ -2259,9 +2259,9 @@ PASS xmlComment.nodeValue = "", with selected range collapsed at (xmlComment, 1) PASS xmlComment.nodeValue = "foo", with unselected range collapsed at (xmlComment, 1) PASS xmlComment.nodeValue = "foo", with selected range collapsed at (xmlComment, 1) -FAIL xmlComment.nodeValue = xmlComment.nodeValue, with unselected range collapsed at (xmlComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlComment.nodeValue = xmlComment.nodeValue, with unselected range collapsed at (xmlComment, 1) PASS xmlComment.nodeValue = xmlComment.nodeValue, with selected range collapsed at (xmlComment, 1) -FAIL xmlComment.nodeValue += "", with unselected range collapsed at (xmlComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlComment.nodeValue += "", with unselected range collapsed at (xmlComment, 1) PASS xmlComment.nodeValue += "", with selected range collapsed at (xmlComment, 1) PASS xmlComment.nodeValue += "foo", with unselected range collapsed at (xmlComment, 1) PASS xmlComment.nodeValue += "foo", with selected range collapsed at (xmlComment, 1) @@ -2271,9 +2271,9 @@ PASS xmlComment.data = "", with selected range on xmlComment from 0 to xmlComment.length PASS xmlComment.data = "foo", with unselected range on xmlComment from 0 to xmlComment.length PASS xmlComment.data = "foo", with selected range on xmlComment from 0 to xmlComment.length -FAIL xmlComment.data = xmlComment.data, with unselected range on xmlComment from 0 to xmlComment.length assert_equals: Wrong end offset expected 0 but got 143 +PASS xmlComment.data = xmlComment.data, with unselected range on xmlComment from 0 to xmlComment.length PASS xmlComment.data = xmlComment.data, with selected range on xmlComment from 0 to xmlComment.length -FAIL xmlComment.data += "", with unselected range on xmlComment from 0 to xmlComment.length assert_equals: Wrong end offset expected 0 but got 143 +PASS xmlComment.data += "", with unselected range on xmlComment from 0 to xmlComment.length PASS xmlComment.data += "", with selected range on xmlComment from 0 to xmlComment.length PASS xmlComment.data += "foo", with unselected range on xmlComment from 0 to xmlComment.length PASS xmlComment.data += "foo", with selected range on xmlComment from 0 to xmlComment.length @@ -2283,9 +2283,9 @@ PASS xmlComment.textContent = "", with selected range on xmlComment from 0 to xmlComment.length PASS xmlComment.textContent = "foo", with unselected range on xmlComment from 0 to xmlComment.length PASS xmlComment.textContent = "foo", with selected range on xmlComment from 0 to xmlComment.length -FAIL xmlComment.textContent = xmlComment.textContent, with unselected range on xmlComment from 0 to xmlComment.length assert_equals: Wrong end offset expected 0 but got 143 +PASS xmlComment.textContent = xmlComment.textContent, with unselected range on xmlComment from 0 to xmlComment.length PASS xmlComment.textContent = xmlComment.textContent, with selected range on xmlComment from 0 to xmlComment.length -FAIL xmlComment.textContent += "", with unselected range on xmlComment from 0 to xmlComment.length assert_equals: Wrong end offset expected 0 but got 143 +PASS xmlComment.textContent += "", with unselected range on xmlComment from 0 to xmlComment.length PASS xmlComment.textContent += "", with selected range on xmlComment from 0 to xmlComment.length PASS xmlComment.textContent += "foo", with unselected range on xmlComment from 0 to xmlComment.length PASS xmlComment.textContent += "foo", with selected range on xmlComment from 0 to xmlComment.length @@ -2295,9 +2295,9 @@ PASS xmlComment.nodeValue = "", with selected range on xmlComment from 0 to xmlComment.length PASS xmlComment.nodeValue = "foo", with unselected range on xmlComment from 0 to xmlComment.length PASS xmlComment.nodeValue = "foo", with selected range on xmlComment from 0 to xmlComment.length -FAIL xmlComment.nodeValue = xmlComment.nodeValue, with unselected range on xmlComment from 0 to xmlComment.length assert_equals: Wrong end offset expected 0 but got 143 +PASS xmlComment.nodeValue = xmlComment.nodeValue, with unselected range on xmlComment from 0 to xmlComment.length PASS xmlComment.nodeValue = xmlComment.nodeValue, with selected range on xmlComment from 0 to xmlComment.length -FAIL xmlComment.nodeValue += "", with unselected range on xmlComment from 0 to xmlComment.length assert_equals: Wrong end offset expected 0 but got 143 +PASS xmlComment.nodeValue += "", with unselected range on xmlComment from 0 to xmlComment.length PASS xmlComment.nodeValue += "", with selected range on xmlComment from 0 to xmlComment.length PASS xmlComment.nodeValue += "foo", with unselected range on xmlComment from 0 to xmlComment.length PASS xmlComment.nodeValue += "foo", with selected range on xmlComment from 0 to xmlComment.length @@ -2307,9 +2307,9 @@ PASS xmlComment.data = "", with selected range on xmlComment from 1 to xmlComment.length PASS xmlComment.data = "foo", with unselected range on xmlComment from 1 to xmlComment.length PASS xmlComment.data = "foo", with selected range on xmlComment from 1 to xmlComment.length -FAIL xmlComment.data = xmlComment.data, with unselected range on xmlComment from 1 to xmlComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlComment.data = xmlComment.data, with unselected range on xmlComment from 1 to xmlComment.length PASS xmlComment.data = xmlComment.data, with selected range on xmlComment from 1 to xmlComment.length -FAIL xmlComment.data += "", with unselected range on xmlComment from 1 to xmlComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlComment.data += "", with unselected range on xmlComment from 1 to xmlComment.length PASS xmlComment.data += "", with selected range on xmlComment from 1 to xmlComment.length PASS xmlComment.data += "foo", with unselected range on xmlComment from 1 to xmlComment.length PASS xmlComment.data += "foo", with selected range on xmlComment from 1 to xmlComment.length @@ -2319,9 +2319,9 @@ PASS xmlComment.textContent = "", with selected range on xmlComment from 1 to xmlComment.length PASS xmlComment.textContent = "foo", with unselected range on xmlComment from 1 to xmlComment.length PASS xmlComment.textContent = "foo", with selected range on xmlComment from 1 to xmlComment.length -FAIL xmlComment.textContent = xmlComment.textContent, with unselected range on xmlComment from 1 to xmlComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlComment.textContent = xmlComment.textContent, with unselected range on xmlComment from 1 to xmlComment.length PASS xmlComment.textContent = xmlComment.textContent, with selected range on xmlComment from 1 to xmlComment.length -FAIL xmlComment.textContent += "", with unselected range on xmlComment from 1 to xmlComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlComment.textContent += "", with unselected range on xmlComment from 1 to xmlComment.length PASS xmlComment.textContent += "", with selected range on xmlComment from 1 to xmlComment.length PASS xmlComment.textContent += "foo", with unselected range on xmlComment from 1 to xmlComment.length PASS xmlComment.textContent += "foo", with selected range on xmlComment from 1 to xmlComment.length @@ -2331,9 +2331,9 @@ PASS xmlComment.nodeValue = "", with selected range on xmlComment from 1 to xmlComment.length PASS xmlComment.nodeValue = "foo", with unselected range on xmlComment from 1 to xmlComment.length PASS xmlComment.nodeValue = "foo", with selected range on xmlComment from 1 to xmlComment.length -FAIL xmlComment.nodeValue = xmlComment.nodeValue, with unselected range on xmlComment from 1 to xmlComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlComment.nodeValue = xmlComment.nodeValue, with unselected range on xmlComment from 1 to xmlComment.length PASS xmlComment.nodeValue = xmlComment.nodeValue, with selected range on xmlComment from 1 to xmlComment.length -FAIL xmlComment.nodeValue += "", with unselected range on xmlComment from 1 to xmlComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS xmlComment.nodeValue += "", with unselected range on xmlComment from 1 to xmlComment.length PASS xmlComment.nodeValue += "", with selected range on xmlComment from 1 to xmlComment.length PASS xmlComment.nodeValue += "foo", with unselected range on xmlComment from 1 to xmlComment.length PASS xmlComment.nodeValue += "foo", with selected range on xmlComment from 1 to xmlComment.length @@ -2343,9 +2343,9 @@ PASS xmlComment.data = "", with selected range collapsed at (xmlComment, xmlComment.length) PASS xmlComment.data = "foo", with unselected range collapsed at (xmlComment, xmlComment.length) PASS xmlComment.data = "foo", with selected range collapsed at (xmlComment, xmlComment.length) -FAIL xmlComment.data = xmlComment.data, with unselected range collapsed at (xmlComment, xmlComment.length) assert_equals: Wrong start offset expected 0 but got 143 +PASS xmlComment.data = xmlComment.data, with unselected range collapsed at (xmlComment, xmlComment.length) PASS xmlComment.data = xmlComment.data, with selected range collapsed at (xmlComment, xmlComment.length) -FAIL xmlComment.data += "", with unselected range collapsed at (xmlComment, xmlComment.length) assert_equals: Wrong start offset expected 0 but got 143 +PASS xmlComment.data += "", with unselected range collapsed at (xmlComment, xmlComment.length) PASS xmlComment.data += "", with selected range collapsed at (xmlComment, xmlComment.length) PASS xmlComment.data += "foo", with unselected range collapsed at (xmlComment, xmlComment.length) PASS xmlComment.data += "foo", with selected range collapsed at (xmlComment, xmlComment.length) @@ -2355,9 +2355,9 @@ PASS xmlComment.textContent = "", with selected range collapsed at (xmlComment, xmlComment.length) PASS xmlComment.textContent = "foo", with unselected range collapsed at (xmlComment, xmlComment.length) PASS xmlComment.textContent = "foo", with selected range collapsed at (xmlComment, xmlComment.length) -FAIL xmlComment.textContent = xmlComment.textContent, with unselected range collapsed at (xmlComment, xmlComment.length) assert_equals: Wrong start offset expected 0 but got 143 +PASS xmlComment.textContent = xmlComment.textContent, with unselected range collapsed at (xmlComment, xmlComment.length) PASS xmlComment.textContent = xmlComment.textContent, with selected range collapsed at (xmlComment, xmlComment.length) -FAIL xmlComment.textContent += "", with unselected range collapsed at (xmlComment, xmlComment.length) assert_equals: Wrong start offset expected 0 but got 143 +PASS xmlComment.textContent += "", with unselected range collapsed at (xmlComment, xmlComment.length) PASS xmlComment.textContent += "", with selected range collapsed at (xmlComment, xmlComment.length) PASS xmlComment.textContent += "foo", with unselected range collapsed at (xmlComment, xmlComment.length) PASS xmlComment.textContent += "foo", with selected range collapsed at (xmlComment, xmlComment.length) @@ -2367,9 +2367,9 @@ PASS xmlComment.nodeValue = "", with selected range collapsed at (xmlComment, xmlComment.length) PASS xmlComment.nodeValue = "foo", with unselected range collapsed at (xmlComment, xmlComment.length) PASS xmlComment.nodeValue = "foo", with selected range collapsed at (xmlComment, xmlComment.length) -FAIL xmlComment.nodeValue = xmlComment.nodeValue, with unselected range collapsed at (xmlComment, xmlComment.length) assert_equals: Wrong start offset expected 0 but got 143 +PASS xmlComment.nodeValue = xmlComment.nodeValue, with unselected range collapsed at (xmlComment, xmlComment.length) PASS xmlComment.nodeValue = xmlComment.nodeValue, with selected range collapsed at (xmlComment, xmlComment.length) -FAIL xmlComment.nodeValue += "", with unselected range collapsed at (xmlComment, xmlComment.length) assert_equals: Wrong start offset expected 0 but got 143 +PASS xmlComment.nodeValue += "", with unselected range collapsed at (xmlComment, xmlComment.length) PASS xmlComment.nodeValue += "", with selected range collapsed at (xmlComment, xmlComment.length) PASS xmlComment.nodeValue += "foo", with unselected range collapsed at (xmlComment, xmlComment.length) PASS xmlComment.nodeValue += "foo", with selected range collapsed at (xmlComment, xmlComment.length) @@ -2415,9 +2415,9 @@ PASS detachedComment.data = "", with selected range on detachedComment from 0 to 1 PASS detachedComment.data = "foo", with unselected range on detachedComment from 0 to 1 PASS detachedComment.data = "foo", with selected range on detachedComment from 0 to 1 -FAIL detachedComment.data = detachedComment.data, with unselected range on detachedComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedComment.data = detachedComment.data, with unselected range on detachedComment from 0 to 1 PASS detachedComment.data = detachedComment.data, with selected range on detachedComment from 0 to 1 -FAIL detachedComment.data += "", with unselected range on detachedComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedComment.data += "", with unselected range on detachedComment from 0 to 1 PASS detachedComment.data += "", with selected range on detachedComment from 0 to 1 PASS detachedComment.data += "foo", with unselected range on detachedComment from 0 to 1 PASS detachedComment.data += "foo", with selected range on detachedComment from 0 to 1 @@ -2427,9 +2427,9 @@ PASS detachedComment.textContent = "", with selected range on detachedComment from 0 to 1 PASS detachedComment.textContent = "foo", with unselected range on detachedComment from 0 to 1 PASS detachedComment.textContent = "foo", with selected range on detachedComment from 0 to 1 -FAIL detachedComment.textContent = detachedComment.textContent, with unselected range on detachedComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedComment.textContent = detachedComment.textContent, with unselected range on detachedComment from 0 to 1 PASS detachedComment.textContent = detachedComment.textContent, with selected range on detachedComment from 0 to 1 -FAIL detachedComment.textContent += "", with unselected range on detachedComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedComment.textContent += "", with unselected range on detachedComment from 0 to 1 PASS detachedComment.textContent += "", with selected range on detachedComment from 0 to 1 PASS detachedComment.textContent += "foo", with unselected range on detachedComment from 0 to 1 PASS detachedComment.textContent += "foo", with selected range on detachedComment from 0 to 1 @@ -2439,9 +2439,9 @@ PASS detachedComment.nodeValue = "", with selected range on detachedComment from 0 to 1 PASS detachedComment.nodeValue = "foo", with unselected range on detachedComment from 0 to 1 PASS detachedComment.nodeValue = "foo", with selected range on detachedComment from 0 to 1 -FAIL detachedComment.nodeValue = detachedComment.nodeValue, with unselected range on detachedComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedComment.nodeValue = detachedComment.nodeValue, with unselected range on detachedComment from 0 to 1 PASS detachedComment.nodeValue = detachedComment.nodeValue, with selected range on detachedComment from 0 to 1 -FAIL detachedComment.nodeValue += "", with unselected range on detachedComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedComment.nodeValue += "", with unselected range on detachedComment from 0 to 1 PASS detachedComment.nodeValue += "", with selected range on detachedComment from 0 to 1 PASS detachedComment.nodeValue += "foo", with unselected range on detachedComment from 0 to 1 PASS detachedComment.nodeValue += "foo", with selected range on detachedComment from 0 to 1 @@ -2451,9 +2451,9 @@ PASS detachedComment.data = "", with selected range collapsed at (detachedComment, 1) PASS detachedComment.data = "foo", with unselected range collapsed at (detachedComment, 1) PASS detachedComment.data = "foo", with selected range collapsed at (detachedComment, 1) -FAIL detachedComment.data = detachedComment.data, with unselected range collapsed at (detachedComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedComment.data = detachedComment.data, with unselected range collapsed at (detachedComment, 1) PASS detachedComment.data = detachedComment.data, with selected range collapsed at (detachedComment, 1) -FAIL detachedComment.data += "", with unselected range collapsed at (detachedComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedComment.data += "", with unselected range collapsed at (detachedComment, 1) PASS detachedComment.data += "", with selected range collapsed at (detachedComment, 1) PASS detachedComment.data += "foo", with unselected range collapsed at (detachedComment, 1) PASS detachedComment.data += "foo", with selected range collapsed at (detachedComment, 1) @@ -2463,9 +2463,9 @@ PASS detachedComment.textContent = "", with selected range collapsed at (detachedComment, 1) PASS detachedComment.textContent = "foo", with unselected range collapsed at (detachedComment, 1) PASS detachedComment.textContent = "foo", with selected range collapsed at (detachedComment, 1) -FAIL detachedComment.textContent = detachedComment.textContent, with unselected range collapsed at (detachedComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedComment.textContent = detachedComment.textContent, with unselected range collapsed at (detachedComment, 1) PASS detachedComment.textContent = detachedComment.textContent, with selected range collapsed at (detachedComment, 1) -FAIL detachedComment.textContent += "", with unselected range collapsed at (detachedComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedComment.textContent += "", with unselected range collapsed at (detachedComment, 1) PASS detachedComment.textContent += "", with selected range collapsed at (detachedComment, 1) PASS detachedComment.textContent += "foo", with unselected range collapsed at (detachedComment, 1) PASS detachedComment.textContent += "foo", with selected range collapsed at (detachedComment, 1) @@ -2475,9 +2475,9 @@ PASS detachedComment.nodeValue = "", with selected range collapsed at (detachedComment, 1) PASS detachedComment.nodeValue = "foo", with unselected range collapsed at (detachedComment, 1) PASS detachedComment.nodeValue = "foo", with selected range collapsed at (detachedComment, 1) -FAIL detachedComment.nodeValue = detachedComment.nodeValue, with unselected range collapsed at (detachedComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedComment.nodeValue = detachedComment.nodeValue, with unselected range collapsed at (detachedComment, 1) PASS detachedComment.nodeValue = detachedComment.nodeValue, with selected range collapsed at (detachedComment, 1) -FAIL detachedComment.nodeValue += "", with unselected range collapsed at (detachedComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedComment.nodeValue += "", with unselected range collapsed at (detachedComment, 1) PASS detachedComment.nodeValue += "", with selected range collapsed at (detachedComment, 1) PASS detachedComment.nodeValue += "foo", with unselected range collapsed at (detachedComment, 1) PASS detachedComment.nodeValue += "foo", with selected range collapsed at (detachedComment, 1) @@ -2487,9 +2487,9 @@ PASS detachedComment.data = "", with selected range on detachedComment from 0 to detachedComment.length PASS detachedComment.data = "foo", with unselected range on detachedComment from 0 to detachedComment.length PASS detachedComment.data = "foo", with selected range on detachedComment from 0 to detachedComment.length -FAIL detachedComment.data = detachedComment.data, with unselected range on detachedComment from 0 to detachedComment.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedComment.data = detachedComment.data, with unselected range on detachedComment from 0 to detachedComment.length PASS detachedComment.data = detachedComment.data, with selected range on detachedComment from 0 to detachedComment.length -FAIL detachedComment.data += "", with unselected range on detachedComment from 0 to detachedComment.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedComment.data += "", with unselected range on detachedComment from 0 to detachedComment.length PASS detachedComment.data += "", with selected range on detachedComment from 0 to detachedComment.length PASS detachedComment.data += "foo", with unselected range on detachedComment from 0 to detachedComment.length PASS detachedComment.data += "foo", with selected range on detachedComment from 0 to detachedComment.length @@ -2499,9 +2499,9 @@ PASS detachedComment.textContent = "", with selected range on detachedComment from 0 to detachedComment.length PASS detachedComment.textContent = "foo", with unselected range on detachedComment from 0 to detachedComment.length PASS detachedComment.textContent = "foo", with selected range on detachedComment from 0 to detachedComment.length -FAIL detachedComment.textContent = detachedComment.textContent, with unselected range on detachedComment from 0 to detachedComment.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedComment.textContent = detachedComment.textContent, with unselected range on detachedComment from 0 to detachedComment.length PASS detachedComment.textContent = detachedComment.textContent, with selected range on detachedComment from 0 to detachedComment.length -FAIL detachedComment.textContent += "", with unselected range on detachedComment from 0 to detachedComment.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedComment.textContent += "", with unselected range on detachedComment from 0 to detachedComment.length PASS detachedComment.textContent += "", with selected range on detachedComment from 0 to detachedComment.length PASS detachedComment.textContent += "foo", with unselected range on detachedComment from 0 to detachedComment.length PASS detachedComment.textContent += "foo", with selected range on detachedComment from 0 to detachedComment.length @@ -2511,9 +2511,9 @@ PASS detachedComment.nodeValue = "", with selected range on detachedComment from 0 to detachedComment.length PASS detachedComment.nodeValue = "foo", with unselected range on detachedComment from 0 to detachedComment.length PASS detachedComment.nodeValue = "foo", with selected range on detachedComment from 0 to detachedComment.length -FAIL detachedComment.nodeValue = detachedComment.nodeValue, with unselected range on detachedComment from 0 to detachedComment.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedComment.nodeValue = detachedComment.nodeValue, with unselected range on detachedComment from 0 to detachedComment.length PASS detachedComment.nodeValue = detachedComment.nodeValue, with selected range on detachedComment from 0 to detachedComment.length -FAIL detachedComment.nodeValue += "", with unselected range on detachedComment from 0 to detachedComment.length assert_equals: Wrong end offset expected 0 but got 8 +PASS detachedComment.nodeValue += "", with unselected range on detachedComment from 0 to detachedComment.length PASS detachedComment.nodeValue += "", with selected range on detachedComment from 0 to detachedComment.length PASS detachedComment.nodeValue += "foo", with unselected range on detachedComment from 0 to detachedComment.length PASS detachedComment.nodeValue += "foo", with selected range on detachedComment from 0 to detachedComment.length @@ -2523,9 +2523,9 @@ PASS detachedComment.data = "", with selected range on detachedComment from 1 to detachedComment.length PASS detachedComment.data = "foo", with unselected range on detachedComment from 1 to detachedComment.length PASS detachedComment.data = "foo", with selected range on detachedComment from 1 to detachedComment.length -FAIL detachedComment.data = detachedComment.data, with unselected range on detachedComment from 1 to detachedComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedComment.data = detachedComment.data, with unselected range on detachedComment from 1 to detachedComment.length PASS detachedComment.data = detachedComment.data, with selected range on detachedComment from 1 to detachedComment.length -FAIL detachedComment.data += "", with unselected range on detachedComment from 1 to detachedComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedComment.data += "", with unselected range on detachedComment from 1 to detachedComment.length PASS detachedComment.data += "", with selected range on detachedComment from 1 to detachedComment.length PASS detachedComment.data += "foo", with unselected range on detachedComment from 1 to detachedComment.length PASS detachedComment.data += "foo", with selected range on detachedComment from 1 to detachedComment.length @@ -2535,9 +2535,9 @@ PASS detachedComment.textContent = "", with selected range on detachedComment from 1 to detachedComment.length PASS detachedComment.textContent = "foo", with unselected range on detachedComment from 1 to detachedComment.length PASS detachedComment.textContent = "foo", with selected range on detachedComment from 1 to detachedComment.length -FAIL detachedComment.textContent = detachedComment.textContent, with unselected range on detachedComment from 1 to detachedComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedComment.textContent = detachedComment.textContent, with unselected range on detachedComment from 1 to detachedComment.length PASS detachedComment.textContent = detachedComment.textContent, with selected range on detachedComment from 1 to detachedComment.length -FAIL detachedComment.textContent += "", with unselected range on detachedComment from 1 to detachedComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedComment.textContent += "", with unselected range on detachedComment from 1 to detachedComment.length PASS detachedComment.textContent += "", with selected range on detachedComment from 1 to detachedComment.length PASS detachedComment.textContent += "foo", with unselected range on detachedComment from 1 to detachedComment.length PASS detachedComment.textContent += "foo", with selected range on detachedComment from 1 to detachedComment.length @@ -2547,9 +2547,9 @@ PASS detachedComment.nodeValue = "", with selected range on detachedComment from 1 to detachedComment.length PASS detachedComment.nodeValue = "foo", with unselected range on detachedComment from 1 to detachedComment.length PASS detachedComment.nodeValue = "foo", with selected range on detachedComment from 1 to detachedComment.length -FAIL detachedComment.nodeValue = detachedComment.nodeValue, with unselected range on detachedComment from 1 to detachedComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedComment.nodeValue = detachedComment.nodeValue, with unselected range on detachedComment from 1 to detachedComment.length PASS detachedComment.nodeValue = detachedComment.nodeValue, with selected range on detachedComment from 1 to detachedComment.length -FAIL detachedComment.nodeValue += "", with unselected range on detachedComment from 1 to detachedComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedComment.nodeValue += "", with unselected range on detachedComment from 1 to detachedComment.length PASS detachedComment.nodeValue += "", with selected range on detachedComment from 1 to detachedComment.length PASS detachedComment.nodeValue += "foo", with unselected range on detachedComment from 1 to detachedComment.length PASS detachedComment.nodeValue += "foo", with selected range on detachedComment from 1 to detachedComment.length @@ -2559,9 +2559,9 @@ PASS detachedComment.data = "", with selected range collapsed at (detachedComment, detachedComment.length) PASS detachedComment.data = "foo", with unselected range collapsed at (detachedComment, detachedComment.length) PASS detachedComment.data = "foo", with selected range collapsed at (detachedComment, detachedComment.length) -FAIL detachedComment.data = detachedComment.data, with unselected range collapsed at (detachedComment, detachedComment.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedComment.data = detachedComment.data, with unselected range collapsed at (detachedComment, detachedComment.length) PASS detachedComment.data = detachedComment.data, with selected range collapsed at (detachedComment, detachedComment.length) -FAIL detachedComment.data += "", with unselected range collapsed at (detachedComment, detachedComment.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedComment.data += "", with unselected range collapsed at (detachedComment, detachedComment.length) PASS detachedComment.data += "", with selected range collapsed at (detachedComment, detachedComment.length) PASS detachedComment.data += "foo", with unselected range collapsed at (detachedComment, detachedComment.length) PASS detachedComment.data += "foo", with selected range collapsed at (detachedComment, detachedComment.length) @@ -2571,9 +2571,9 @@ PASS detachedComment.textContent = "", with selected range collapsed at (detachedComment, detachedComment.length) PASS detachedComment.textContent = "foo", with unselected range collapsed at (detachedComment, detachedComment.length) PASS detachedComment.textContent = "foo", with selected range collapsed at (detachedComment, detachedComment.length) -FAIL detachedComment.textContent = detachedComment.textContent, with unselected range collapsed at (detachedComment, detachedComment.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedComment.textContent = detachedComment.textContent, with unselected range collapsed at (detachedComment, detachedComment.length) PASS detachedComment.textContent = detachedComment.textContent, with selected range collapsed at (detachedComment, detachedComment.length) -FAIL detachedComment.textContent += "", with unselected range collapsed at (detachedComment, detachedComment.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedComment.textContent += "", with unselected range collapsed at (detachedComment, detachedComment.length) PASS detachedComment.textContent += "", with selected range collapsed at (detachedComment, detachedComment.length) PASS detachedComment.textContent += "foo", with unselected range collapsed at (detachedComment, detachedComment.length) PASS detachedComment.textContent += "foo", with selected range collapsed at (detachedComment, detachedComment.length) @@ -2583,9 +2583,9 @@ PASS detachedComment.nodeValue = "", with selected range collapsed at (detachedComment, detachedComment.length) PASS detachedComment.nodeValue = "foo", with unselected range collapsed at (detachedComment, detachedComment.length) PASS detachedComment.nodeValue = "foo", with selected range collapsed at (detachedComment, detachedComment.length) -FAIL detachedComment.nodeValue = detachedComment.nodeValue, with unselected range collapsed at (detachedComment, detachedComment.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedComment.nodeValue = detachedComment.nodeValue, with unselected range collapsed at (detachedComment, detachedComment.length) PASS detachedComment.nodeValue = detachedComment.nodeValue, with selected range collapsed at (detachedComment, detachedComment.length) -FAIL detachedComment.nodeValue += "", with unselected range collapsed at (detachedComment, detachedComment.length) assert_equals: Wrong start offset expected 0 but got 8 +PASS detachedComment.nodeValue += "", with unselected range collapsed at (detachedComment, detachedComment.length) PASS detachedComment.nodeValue += "", with selected range collapsed at (detachedComment, detachedComment.length) PASS detachedComment.nodeValue += "foo", with unselected range collapsed at (detachedComment, detachedComment.length) PASS detachedComment.nodeValue += "foo", with selected range collapsed at (detachedComment, detachedComment.length) @@ -2631,9 +2631,9 @@ PASS detachedForeignComment.data = "", with selected range on detachedForeignComment from 0 to 1 PASS detachedForeignComment.data = "foo", with unselected range on detachedForeignComment from 0 to 1 PASS detachedForeignComment.data = "foo", with selected range on detachedForeignComment from 0 to 1 -FAIL detachedForeignComment.data = detachedForeignComment.data, with unselected range on detachedForeignComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedForeignComment.data = detachedForeignComment.data, with unselected range on detachedForeignComment from 0 to 1 PASS detachedForeignComment.data = detachedForeignComment.data, with selected range on detachedForeignComment from 0 to 1 -FAIL detachedForeignComment.data += "", with unselected range on detachedForeignComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedForeignComment.data += "", with unselected range on detachedForeignComment from 0 to 1 PASS detachedForeignComment.data += "", with selected range on detachedForeignComment from 0 to 1 PASS detachedForeignComment.data += "foo", with unselected range on detachedForeignComment from 0 to 1 PASS detachedForeignComment.data += "foo", with selected range on detachedForeignComment from 0 to 1 @@ -2643,9 +2643,9 @@ PASS detachedForeignComment.textContent = "", with selected range on detachedForeignComment from 0 to 1 PASS detachedForeignComment.textContent = "foo", with unselected range on detachedForeignComment from 0 to 1 PASS detachedForeignComment.textContent = "foo", with selected range on detachedForeignComment from 0 to 1 -FAIL detachedForeignComment.textContent = detachedForeignComment.textContent, with unselected range on detachedForeignComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedForeignComment.textContent = detachedForeignComment.textContent, with unselected range on detachedForeignComment from 0 to 1 PASS detachedForeignComment.textContent = detachedForeignComment.textContent, with selected range on detachedForeignComment from 0 to 1 -FAIL detachedForeignComment.textContent += "", with unselected range on detachedForeignComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedForeignComment.textContent += "", with unselected range on detachedForeignComment from 0 to 1 PASS detachedForeignComment.textContent += "", with selected range on detachedForeignComment from 0 to 1 PASS detachedForeignComment.textContent += "foo", with unselected range on detachedForeignComment from 0 to 1 PASS detachedForeignComment.textContent += "foo", with selected range on detachedForeignComment from 0 to 1 @@ -2655,9 +2655,9 @@ PASS detachedForeignComment.nodeValue = "", with selected range on detachedForeignComment from 0 to 1 PASS detachedForeignComment.nodeValue = "foo", with unselected range on detachedForeignComment from 0 to 1 PASS detachedForeignComment.nodeValue = "foo", with selected range on detachedForeignComment from 0 to 1 -FAIL detachedForeignComment.nodeValue = detachedForeignComment.nodeValue, with unselected range on detachedForeignComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedForeignComment.nodeValue = detachedForeignComment.nodeValue, with unselected range on detachedForeignComment from 0 to 1 PASS detachedForeignComment.nodeValue = detachedForeignComment.nodeValue, with selected range on detachedForeignComment from 0 to 1 -FAIL detachedForeignComment.nodeValue += "", with unselected range on detachedForeignComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedForeignComment.nodeValue += "", with unselected range on detachedForeignComment from 0 to 1 PASS detachedForeignComment.nodeValue += "", with selected range on detachedForeignComment from 0 to 1 PASS detachedForeignComment.nodeValue += "foo", with unselected range on detachedForeignComment from 0 to 1 PASS detachedForeignComment.nodeValue += "foo", with selected range on detachedForeignComment from 0 to 1 @@ -2667,9 +2667,9 @@ PASS detachedForeignComment.data = "", with selected range collapsed at (detachedForeignComment, 1) PASS detachedForeignComment.data = "foo", with unselected range collapsed at (detachedForeignComment, 1) PASS detachedForeignComment.data = "foo", with selected range collapsed at (detachedForeignComment, 1) -FAIL detachedForeignComment.data = detachedForeignComment.data, with unselected range collapsed at (detachedForeignComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignComment.data = detachedForeignComment.data, with unselected range collapsed at (detachedForeignComment, 1) PASS detachedForeignComment.data = detachedForeignComment.data, with selected range collapsed at (detachedForeignComment, 1) -FAIL detachedForeignComment.data += "", with unselected range collapsed at (detachedForeignComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignComment.data += "", with unselected range collapsed at (detachedForeignComment, 1) PASS detachedForeignComment.data += "", with selected range collapsed at (detachedForeignComment, 1) PASS detachedForeignComment.data += "foo", with unselected range collapsed at (detachedForeignComment, 1) PASS detachedForeignComment.data += "foo", with selected range collapsed at (detachedForeignComment, 1) @@ -2679,9 +2679,9 @@ PASS detachedForeignComment.textContent = "", with selected range collapsed at (detachedForeignComment, 1) PASS detachedForeignComment.textContent = "foo", with unselected range collapsed at (detachedForeignComment, 1) PASS detachedForeignComment.textContent = "foo", with selected range collapsed at (detachedForeignComment, 1) -FAIL detachedForeignComment.textContent = detachedForeignComment.textContent, with unselected range collapsed at (detachedForeignComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignComment.textContent = detachedForeignComment.textContent, with unselected range collapsed at (detachedForeignComment, 1) PASS detachedForeignComment.textContent = detachedForeignComment.textContent, with selected range collapsed at (detachedForeignComment, 1) -FAIL detachedForeignComment.textContent += "", with unselected range collapsed at (detachedForeignComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignComment.textContent += "", with unselected range collapsed at (detachedForeignComment, 1) PASS detachedForeignComment.textContent += "", with selected range collapsed at (detachedForeignComment, 1) PASS detachedForeignComment.textContent += "foo", with unselected range collapsed at (detachedForeignComment, 1) PASS detachedForeignComment.textContent += "foo", with selected range collapsed at (detachedForeignComment, 1) @@ -2691,9 +2691,9 @@ PASS detachedForeignComment.nodeValue = "", with selected range collapsed at (detachedForeignComment, 1) PASS detachedForeignComment.nodeValue = "foo", with unselected range collapsed at (detachedForeignComment, 1) PASS detachedForeignComment.nodeValue = "foo", with selected range collapsed at (detachedForeignComment, 1) -FAIL detachedForeignComment.nodeValue = detachedForeignComment.nodeValue, with unselected range collapsed at (detachedForeignComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignComment.nodeValue = detachedForeignComment.nodeValue, with unselected range collapsed at (detachedForeignComment, 1) PASS detachedForeignComment.nodeValue = detachedForeignComment.nodeValue, with selected range collapsed at (detachedForeignComment, 1) -FAIL detachedForeignComment.nodeValue += "", with unselected range collapsed at (detachedForeignComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignComment.nodeValue += "", with unselected range collapsed at (detachedForeignComment, 1) PASS detachedForeignComment.nodeValue += "", with selected range collapsed at (detachedForeignComment, 1) PASS detachedForeignComment.nodeValue += "foo", with unselected range collapsed at (detachedForeignComment, 1) PASS detachedForeignComment.nodeValue += "foo", with selected range collapsed at (detachedForeignComment, 1) @@ -2703,9 +2703,9 @@ PASS detachedForeignComment.data = "", with selected range on detachedForeignComment from 0 to detachedForeignComment.length PASS detachedForeignComment.data = "foo", with unselected range on detachedForeignComment from 0 to detachedForeignComment.length PASS detachedForeignComment.data = "foo", with selected range on detachedForeignComment from 0 to detachedForeignComment.length -FAIL detachedForeignComment.data = detachedForeignComment.data, with unselected range on detachedForeignComment from 0 to detachedForeignComment.length assert_equals: Wrong end offset expected 0 but got 19 +PASS detachedForeignComment.data = detachedForeignComment.data, with unselected range on detachedForeignComment from 0 to detachedForeignComment.length PASS detachedForeignComment.data = detachedForeignComment.data, with selected range on detachedForeignComment from 0 to detachedForeignComment.length -FAIL detachedForeignComment.data += "", with unselected range on detachedForeignComment from 0 to detachedForeignComment.length assert_equals: Wrong end offset expected 0 but got 19 +PASS detachedForeignComment.data += "", with unselected range on detachedForeignComment from 0 to detachedForeignComment.length PASS detachedForeignComment.data += "", with selected range on detachedForeignComment from 0 to detachedForeignComment.length PASS detachedForeignComment.data += "foo", with unselected range on detachedForeignComment from 0 to detachedForeignComment.length PASS detachedForeignComment.data += "foo", with selected range on detachedForeignComment from 0 to detachedForeignComment.length @@ -2715,9 +2715,9 @@ PASS detachedForeignComment.textContent = "", with selected range on detachedForeignComment from 0 to detachedForeignComment.length PASS detachedForeignComment.textContent = "foo", with unselected range on detachedForeignComment from 0 to detachedForeignComment.length PASS detachedForeignComment.textContent = "foo", with selected range on detachedForeignComment from 0 to detachedForeignComment.length -FAIL detachedForeignComment.textContent = detachedForeignComment.textContent, with unselected range on detachedForeignComment from 0 to detachedForeignComment.length assert_equals: Wrong end offset expected 0 but got 19 +PASS detachedForeignComment.textContent = detachedForeignComment.textContent, with unselected range on detachedForeignComment from 0 to detachedForeignComment.length PASS detachedForeignComment.textContent = detachedForeignComment.textContent, with selected range on detachedForeignComment from 0 to detachedForeignComment.length -FAIL detachedForeignComment.textContent += "", with unselected range on detachedForeignComment from 0 to detachedForeignComment.length assert_equals: Wrong end offset expected 0 but got 19 +PASS detachedForeignComment.textContent += "", with unselected range on detachedForeignComment from 0 to detachedForeignComment.length PASS detachedForeignComment.textContent += "", with selected range on detachedForeignComment from 0 to detachedForeignComment.length PASS detachedForeignComment.textContent += "foo", with unselected range on detachedForeignComment from 0 to detachedForeignComment.length PASS detachedForeignComment.textContent += "foo", with selected range on detachedForeignComment from 0 to detachedForeignComment.length @@ -2727,9 +2727,9 @@ PASS detachedForeignComment.nodeValue = "", with selected range on detachedForeignComment from 0 to detachedForeignComment.length PASS detachedForeignComment.nodeValue = "foo", with unselected range on detachedForeignComment from 0 to detachedForeignComment.length PASS detachedForeignComment.nodeValue = "foo", with selected range on detachedForeignComment from 0 to detachedForeignComment.length -FAIL detachedForeignComment.nodeValue = detachedForeignComment.nodeValue, with unselected range on detachedForeignComment from 0 to detachedForeignComment.length assert_equals: Wrong end offset expected 0 but got 19 +PASS detachedForeignComment.nodeValue = detachedForeignComment.nodeValue, with unselected range on detachedForeignComment from 0 to detachedForeignComment.length PASS detachedForeignComment.nodeValue = detachedForeignComment.nodeValue, with selected range on detachedForeignComment from 0 to detachedForeignComment.length -FAIL detachedForeignComment.nodeValue += "", with unselected range on detachedForeignComment from 0 to detachedForeignComment.length assert_equals: Wrong end offset expected 0 but got 19 +PASS detachedForeignComment.nodeValue += "", with unselected range on detachedForeignComment from 0 to detachedForeignComment.length PASS detachedForeignComment.nodeValue += "", with selected range on detachedForeignComment from 0 to detachedForeignComment.length PASS detachedForeignComment.nodeValue += "foo", with unselected range on detachedForeignComment from 0 to detachedForeignComment.length PASS detachedForeignComment.nodeValue += "foo", with selected range on detachedForeignComment from 0 to detachedForeignComment.length @@ -2739,9 +2739,9 @@ PASS detachedForeignComment.data = "", with selected range on detachedForeignComment from 1 to detachedForeignComment.length PASS detachedForeignComment.data = "foo", with unselected range on detachedForeignComment from 1 to detachedForeignComment.length PASS detachedForeignComment.data = "foo", with selected range on detachedForeignComment from 1 to detachedForeignComment.length -FAIL detachedForeignComment.data = detachedForeignComment.data, with unselected range on detachedForeignComment from 1 to detachedForeignComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignComment.data = detachedForeignComment.data, with unselected range on detachedForeignComment from 1 to detachedForeignComment.length PASS detachedForeignComment.data = detachedForeignComment.data, with selected range on detachedForeignComment from 1 to detachedForeignComment.length -FAIL detachedForeignComment.data += "", with unselected range on detachedForeignComment from 1 to detachedForeignComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignComment.data += "", with unselected range on detachedForeignComment from 1 to detachedForeignComment.length PASS detachedForeignComment.data += "", with selected range on detachedForeignComment from 1 to detachedForeignComment.length PASS detachedForeignComment.data += "foo", with unselected range on detachedForeignComment from 1 to detachedForeignComment.length PASS detachedForeignComment.data += "foo", with selected range on detachedForeignComment from 1 to detachedForeignComment.length @@ -2751,9 +2751,9 @@ PASS detachedForeignComment.textContent = "", with selected range on detachedForeignComment from 1 to detachedForeignComment.length PASS detachedForeignComment.textContent = "foo", with unselected range on detachedForeignComment from 1 to detachedForeignComment.length PASS detachedForeignComment.textContent = "foo", with selected range on detachedForeignComment from 1 to detachedForeignComment.length -FAIL detachedForeignComment.textContent = detachedForeignComment.textContent, with unselected range on detachedForeignComment from 1 to detachedForeignComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignComment.textContent = detachedForeignComment.textContent, with unselected range on detachedForeignComment from 1 to detachedForeignComment.length PASS detachedForeignComment.textContent = detachedForeignComment.textContent, with selected range on detachedForeignComment from 1 to detachedForeignComment.length -FAIL detachedForeignComment.textContent += "", with unselected range on detachedForeignComment from 1 to detachedForeignComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignComment.textContent += "", with unselected range on detachedForeignComment from 1 to detachedForeignComment.length PASS detachedForeignComment.textContent += "", with selected range on detachedForeignComment from 1 to detachedForeignComment.length PASS detachedForeignComment.textContent += "foo", with unselected range on detachedForeignComment from 1 to detachedForeignComment.length PASS detachedForeignComment.textContent += "foo", with selected range on detachedForeignComment from 1 to detachedForeignComment.length @@ -2763,9 +2763,9 @@ PASS detachedForeignComment.nodeValue = "", with selected range on detachedForeignComment from 1 to detachedForeignComment.length PASS detachedForeignComment.nodeValue = "foo", with unselected range on detachedForeignComment from 1 to detachedForeignComment.length PASS detachedForeignComment.nodeValue = "foo", with selected range on detachedForeignComment from 1 to detachedForeignComment.length -FAIL detachedForeignComment.nodeValue = detachedForeignComment.nodeValue, with unselected range on detachedForeignComment from 1 to detachedForeignComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignComment.nodeValue = detachedForeignComment.nodeValue, with unselected range on detachedForeignComment from 1 to detachedForeignComment.length PASS detachedForeignComment.nodeValue = detachedForeignComment.nodeValue, with selected range on detachedForeignComment from 1 to detachedForeignComment.length -FAIL detachedForeignComment.nodeValue += "", with unselected range on detachedForeignComment from 1 to detachedForeignComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedForeignComment.nodeValue += "", with unselected range on detachedForeignComment from 1 to detachedForeignComment.length PASS detachedForeignComment.nodeValue += "", with selected range on detachedForeignComment from 1 to detachedForeignComment.length PASS detachedForeignComment.nodeValue += "foo", with unselected range on detachedForeignComment from 1 to detachedForeignComment.length PASS detachedForeignComment.nodeValue += "foo", with selected range on detachedForeignComment from 1 to detachedForeignComment.length @@ -2775,9 +2775,9 @@ PASS detachedForeignComment.data = "", with selected range collapsed at (detachedForeignComment, detachedForeignComment.length) PASS detachedForeignComment.data = "foo", with unselected range collapsed at (detachedForeignComment, detachedForeignComment.length) PASS detachedForeignComment.data = "foo", with selected range collapsed at (detachedForeignComment, detachedForeignComment.length) -FAIL detachedForeignComment.data = detachedForeignComment.data, with unselected range collapsed at (detachedForeignComment, detachedForeignComment.length) assert_equals: Wrong start offset expected 0 but got 19 +PASS detachedForeignComment.data = detachedForeignComment.data, with unselected range collapsed at (detachedForeignComment, detachedForeignComment.length) PASS detachedForeignComment.data = detachedForeignComment.data, with selected range collapsed at (detachedForeignComment, detachedForeignComment.length) -FAIL detachedForeignComment.data += "", with unselected range collapsed at (detachedForeignComment, detachedForeignComment.length) assert_equals: Wrong start offset expected 0 but got 19 +PASS detachedForeignComment.data += "", with unselected range collapsed at (detachedForeignComment, detachedForeignComment.length) PASS detachedForeignComment.data += "", with selected range collapsed at (detachedForeignComment, detachedForeignComment.length) PASS detachedForeignComment.data += "foo", with unselected range collapsed at (detachedForeignComment, detachedForeignComment.length) PASS detachedForeignComment.data += "foo", with selected range collapsed at (detachedForeignComment, detachedForeignComment.length) @@ -2787,9 +2787,9 @@ PASS detachedForeignComment.textContent = "", with selected range collapsed at (detachedForeignComment, detachedForeignComment.length) PASS detachedForeignComment.textContent = "foo", with unselected range collapsed at (detachedForeignComment, detachedForeignComment.length) PASS detachedForeignComment.textContent = "foo", with selected range collapsed at (detachedForeignComment, detachedForeignComment.length) -FAIL detachedForeignComment.textContent = detachedForeignComment.textContent, with unselected range collapsed at (detachedForeignComment, detachedForeignComment.length) assert_equals: Wrong start offset expected 0 but got 19 +PASS detachedForeignComment.textContent = detachedForeignComment.textContent, with unselected range collapsed at (detachedForeignComment, detachedForeignComment.length) PASS detachedForeignComment.textContent = detachedForeignComment.textContent, with selected range collapsed at (detachedForeignComment, detachedForeignComment.length) -FAIL detachedForeignComment.textContent += "", with unselected range collapsed at (detachedForeignComment, detachedForeignComment.length) assert_equals: Wrong start offset expected 0 but got 19 +PASS detachedForeignComment.textContent += "", with unselected range collapsed at (detachedForeignComment, detachedForeignComment.length) PASS detachedForeignComment.textContent += "", with selected range collapsed at (detachedForeignComment, detachedForeignComment.length) PASS detachedForeignComment.textContent += "foo", with unselected range collapsed at (detachedForeignComment, detachedForeignComment.length) PASS detachedForeignComment.textContent += "foo", with selected range collapsed at (detachedForeignComment, detachedForeignComment.length) @@ -2799,9 +2799,9 @@ PASS detachedForeignComment.nodeValue = "", with selected range collapsed at (detachedForeignComment, detachedForeignComment.length) PASS detachedForeignComment.nodeValue = "foo", with unselected range collapsed at (detachedForeignComment, detachedForeignComment.length) PASS detachedForeignComment.nodeValue = "foo", with selected range collapsed at (detachedForeignComment, detachedForeignComment.length) -FAIL detachedForeignComment.nodeValue = detachedForeignComment.nodeValue, with unselected range collapsed at (detachedForeignComment, detachedForeignComment.length) assert_equals: Wrong start offset expected 0 but got 19 +PASS detachedForeignComment.nodeValue = detachedForeignComment.nodeValue, with unselected range collapsed at (detachedForeignComment, detachedForeignComment.length) PASS detachedForeignComment.nodeValue = detachedForeignComment.nodeValue, with selected range collapsed at (detachedForeignComment, detachedForeignComment.length) -FAIL detachedForeignComment.nodeValue += "", with unselected range collapsed at (detachedForeignComment, detachedForeignComment.length) assert_equals: Wrong start offset expected 0 but got 19 +PASS detachedForeignComment.nodeValue += "", with unselected range collapsed at (detachedForeignComment, detachedForeignComment.length) PASS detachedForeignComment.nodeValue += "", with selected range collapsed at (detachedForeignComment, detachedForeignComment.length) PASS detachedForeignComment.nodeValue += "foo", with unselected range collapsed at (detachedForeignComment, detachedForeignComment.length) PASS detachedForeignComment.nodeValue += "foo", with selected range collapsed at (detachedForeignComment, detachedForeignComment.length) @@ -2847,9 +2847,9 @@ PASS detachedXmlComment.data = "", with selected range on detachedXmlComment from 0 to 1 PASS detachedXmlComment.data = "foo", with unselected range on detachedXmlComment from 0 to 1 PASS detachedXmlComment.data = "foo", with selected range on detachedXmlComment from 0 to 1 -FAIL detachedXmlComment.data = detachedXmlComment.data, with unselected range on detachedXmlComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedXmlComment.data = detachedXmlComment.data, with unselected range on detachedXmlComment from 0 to 1 PASS detachedXmlComment.data = detachedXmlComment.data, with selected range on detachedXmlComment from 0 to 1 -FAIL detachedXmlComment.data += "", with unselected range on detachedXmlComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedXmlComment.data += "", with unselected range on detachedXmlComment from 0 to 1 PASS detachedXmlComment.data += "", with selected range on detachedXmlComment from 0 to 1 PASS detachedXmlComment.data += "foo", with unselected range on detachedXmlComment from 0 to 1 PASS detachedXmlComment.data += "foo", with selected range on detachedXmlComment from 0 to 1 @@ -2859,9 +2859,9 @@ PASS detachedXmlComment.textContent = "", with selected range on detachedXmlComment from 0 to 1 PASS detachedXmlComment.textContent = "foo", with unselected range on detachedXmlComment from 0 to 1 PASS detachedXmlComment.textContent = "foo", with selected range on detachedXmlComment from 0 to 1 -FAIL detachedXmlComment.textContent = detachedXmlComment.textContent, with unselected range on detachedXmlComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedXmlComment.textContent = detachedXmlComment.textContent, with unselected range on detachedXmlComment from 0 to 1 PASS detachedXmlComment.textContent = detachedXmlComment.textContent, with selected range on detachedXmlComment from 0 to 1 -FAIL detachedXmlComment.textContent += "", with unselected range on detachedXmlComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedXmlComment.textContent += "", with unselected range on detachedXmlComment from 0 to 1 PASS detachedXmlComment.textContent += "", with selected range on detachedXmlComment from 0 to 1 PASS detachedXmlComment.textContent += "foo", with unselected range on detachedXmlComment from 0 to 1 PASS detachedXmlComment.textContent += "foo", with selected range on detachedXmlComment from 0 to 1 @@ -2871,9 +2871,9 @@ PASS detachedXmlComment.nodeValue = "", with selected range on detachedXmlComment from 0 to 1 PASS detachedXmlComment.nodeValue = "foo", with unselected range on detachedXmlComment from 0 to 1 PASS detachedXmlComment.nodeValue = "foo", with selected range on detachedXmlComment from 0 to 1 -FAIL detachedXmlComment.nodeValue = detachedXmlComment.nodeValue, with unselected range on detachedXmlComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedXmlComment.nodeValue = detachedXmlComment.nodeValue, with unselected range on detachedXmlComment from 0 to 1 PASS detachedXmlComment.nodeValue = detachedXmlComment.nodeValue, with selected range on detachedXmlComment from 0 to 1 -FAIL detachedXmlComment.nodeValue += "", with unselected range on detachedXmlComment from 0 to 1 assert_equals: Wrong end offset expected 0 but got 1 +PASS detachedXmlComment.nodeValue += "", with unselected range on detachedXmlComment from 0 to 1 PASS detachedXmlComment.nodeValue += "", with selected range on detachedXmlComment from 0 to 1 PASS detachedXmlComment.nodeValue += "foo", with unselected range on detachedXmlComment from 0 to 1 PASS detachedXmlComment.nodeValue += "foo", with selected range on detachedXmlComment from 0 to 1 @@ -2883,9 +2883,9 @@ PASS detachedXmlComment.data = "", with selected range collapsed at (detachedXmlComment, 1) PASS detachedXmlComment.data = "foo", with unselected range collapsed at (detachedXmlComment, 1) PASS detachedXmlComment.data = "foo", with selected range collapsed at (detachedXmlComment, 1) -FAIL detachedXmlComment.data = detachedXmlComment.data, with unselected range collapsed at (detachedXmlComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlComment.data = detachedXmlComment.data, with unselected range collapsed at (detachedXmlComment, 1) PASS detachedXmlComment.data = detachedXmlComment.data, with selected range collapsed at (detachedXmlComment, 1) -FAIL detachedXmlComment.data += "", with unselected range collapsed at (detachedXmlComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlComment.data += "", with unselected range collapsed at (detachedXmlComment, 1) PASS detachedXmlComment.data += "", with selected range collapsed at (detachedXmlComment, 1) PASS detachedXmlComment.data += "foo", with unselected range collapsed at (detachedXmlComment, 1) PASS detachedXmlComment.data += "foo", with selected range collapsed at (detachedXmlComment, 1) @@ -2895,9 +2895,9 @@ PASS detachedXmlComment.textContent = "", with selected range collapsed at (detachedXmlComment, 1) PASS detachedXmlComment.textContent = "foo", with unselected range collapsed at (detachedXmlComment, 1) PASS detachedXmlComment.textContent = "foo", with selected range collapsed at (detachedXmlComment, 1) -FAIL detachedXmlComment.textContent = detachedXmlComment.textContent, with unselected range collapsed at (detachedXmlComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlComment.textContent = detachedXmlComment.textContent, with unselected range collapsed at (detachedXmlComment, 1) PASS detachedXmlComment.textContent = detachedXmlComment.textContent, with selected range collapsed at (detachedXmlComment, 1) -FAIL detachedXmlComment.textContent += "", with unselected range collapsed at (detachedXmlComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlComment.textContent += "", with unselected range collapsed at (detachedXmlComment, 1) PASS detachedXmlComment.textContent += "", with selected range collapsed at (detachedXmlComment, 1) PASS detachedXmlComment.textContent += "foo", with unselected range collapsed at (detachedXmlComment, 1) PASS detachedXmlComment.textContent += "foo", with selected range collapsed at (detachedXmlComment, 1) @@ -2907,9 +2907,9 @@ PASS detachedXmlComment.nodeValue = "", with selected range collapsed at (detachedXmlComment, 1) PASS detachedXmlComment.nodeValue = "foo", with unselected range collapsed at (detachedXmlComment, 1) PASS detachedXmlComment.nodeValue = "foo", with selected range collapsed at (detachedXmlComment, 1) -FAIL detachedXmlComment.nodeValue = detachedXmlComment.nodeValue, with unselected range collapsed at (detachedXmlComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlComment.nodeValue = detachedXmlComment.nodeValue, with unselected range collapsed at (detachedXmlComment, 1) PASS detachedXmlComment.nodeValue = detachedXmlComment.nodeValue, with selected range collapsed at (detachedXmlComment, 1) -FAIL detachedXmlComment.nodeValue += "", with unselected range collapsed at (detachedXmlComment, 1) assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlComment.nodeValue += "", with unselected range collapsed at (detachedXmlComment, 1) PASS detachedXmlComment.nodeValue += "", with selected range collapsed at (detachedXmlComment, 1) PASS detachedXmlComment.nodeValue += "foo", with unselected range collapsed at (detachedXmlComment, 1) PASS detachedXmlComment.nodeValue += "foo", with selected range collapsed at (detachedXmlComment, 1) @@ -2919,9 +2919,9 @@ PASS detachedXmlComment.data = "", with selected range on detachedXmlComment from 0 to detachedXmlComment.length PASS detachedXmlComment.data = "foo", with unselected range on detachedXmlComment from 0 to detachedXmlComment.length PASS detachedXmlComment.data = "foo", with selected range on detachedXmlComment from 0 to detachedXmlComment.length -FAIL detachedXmlComment.data = detachedXmlComment.data, with unselected range on detachedXmlComment from 0 to detachedXmlComment.length assert_equals: Wrong end offset expected 0 but got 26 +PASS detachedXmlComment.data = detachedXmlComment.data, with unselected range on detachedXmlComment from 0 to detachedXmlComment.length PASS detachedXmlComment.data = detachedXmlComment.data, with selected range on detachedXmlComment from 0 to detachedXmlComment.length -FAIL detachedXmlComment.data += "", with unselected range on detachedXmlComment from 0 to detachedXmlComment.length assert_equals: Wrong end offset expected 0 but got 26 +PASS detachedXmlComment.data += "", with unselected range on detachedXmlComment from 0 to detachedXmlComment.length PASS detachedXmlComment.data += "", with selected range on detachedXmlComment from 0 to detachedXmlComment.length PASS detachedXmlComment.data += "foo", with unselected range on detachedXmlComment from 0 to detachedXmlComment.length PASS detachedXmlComment.data += "foo", with selected range on detachedXmlComment from 0 to detachedXmlComment.length @@ -2931,9 +2931,9 @@ PASS detachedXmlComment.textContent = "", with selected range on detachedXmlComment from 0 to detachedXmlComment.length PASS detachedXmlComment.textContent = "foo", with unselected range on detachedXmlComment from 0 to detachedXmlComment.length PASS detachedXmlComment.textContent = "foo", with selected range on detachedXmlComment from 0 to detachedXmlComment.length -FAIL detachedXmlComment.textContent = detachedXmlComment.textContent, with unselected range on detachedXmlComment from 0 to detachedXmlComment.length assert_equals: Wrong end offset expected 0 but got 26 +PASS detachedXmlComment.textContent = detachedXmlComment.textContent, with unselected range on detachedXmlComment from 0 to detachedXmlComment.length PASS detachedXmlComment.textContent = detachedXmlComment.textContent, with selected range on detachedXmlComment from 0 to detachedXmlComment.length -FAIL detachedXmlComment.textContent += "", with unselected range on detachedXmlComment from 0 to detachedXmlComment.length assert_equals: Wrong end offset expected 0 but got 26 +PASS detachedXmlComment.textContent += "", with unselected range on detachedXmlComment from 0 to detachedXmlComment.length PASS detachedXmlComment.textContent += "", with selected range on detachedXmlComment from 0 to detachedXmlComment.length PASS detachedXmlComment.textContent += "foo", with unselected range on detachedXmlComment from 0 to detachedXmlComment.length PASS detachedXmlComment.textContent += "foo", with selected range on detachedXmlComment from 0 to detachedXmlComment.length @@ -2943,9 +2943,9 @@ PASS detachedXmlComment.nodeValue = "", with selected range on detachedXmlComment from 0 to detachedXmlComment.length PASS detachedXmlComment.nodeValue = "foo", with unselected range on detachedXmlComment from 0 to detachedXmlComment.length PASS detachedXmlComment.nodeValue = "foo", with selected range on detachedXmlComment from 0 to detachedXmlComment.length -FAIL detachedXmlComment.nodeValue = detachedXmlComment.nodeValue, with unselected range on detachedXmlComment from 0 to detachedXmlComment.length assert_equals: Wrong end offset expected 0 but got 26 +PASS detachedXmlComment.nodeValue = detachedXmlComment.nodeValue, with unselected range on detachedXmlComment from 0 to detachedXmlComment.length PASS detachedXmlComment.nodeValue = detachedXmlComment.nodeValue, with selected range on detachedXmlComment from 0 to detachedXmlComment.length -FAIL detachedXmlComment.nodeValue += "", with unselected range on detachedXmlComment from 0 to detachedXmlComment.length assert_equals: Wrong end offset expected 0 but got 26 +PASS detachedXmlComment.nodeValue += "", with unselected range on detachedXmlComment from 0 to detachedXmlComment.length PASS detachedXmlComment.nodeValue += "", with selected range on detachedXmlComment from 0 to detachedXmlComment.length PASS detachedXmlComment.nodeValue += "foo", with unselected range on detachedXmlComment from 0 to detachedXmlComment.length PASS detachedXmlComment.nodeValue += "foo", with selected range on detachedXmlComment from 0 to detachedXmlComment.length @@ -2955,9 +2955,9 @@ PASS detachedXmlComment.data = "", with selected range on detachedXmlComment from 1 to detachedXmlComment.length PASS detachedXmlComment.data = "foo", with unselected range on detachedXmlComment from 1 to detachedXmlComment.length PASS detachedXmlComment.data = "foo", with selected range on detachedXmlComment from 1 to detachedXmlComment.length -FAIL detachedXmlComment.data = detachedXmlComment.data, with unselected range on detachedXmlComment from 1 to detachedXmlComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlComment.data = detachedXmlComment.data, with unselected range on detachedXmlComment from 1 to detachedXmlComment.length PASS detachedXmlComment.data = detachedXmlComment.data, with selected range on detachedXmlComment from 1 to detachedXmlComment.length -FAIL detachedXmlComment.data += "", with unselected range on detachedXmlComment from 1 to detachedXmlComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlComment.data += "", with unselected range on detachedXmlComment from 1 to detachedXmlComment.length PASS detachedXmlComment.data += "", with selected range on detachedXmlComment from 1 to detachedXmlComment.length PASS detachedXmlComment.data += "foo", with unselected range on detachedXmlComment from 1 to detachedXmlComment.length PASS detachedXmlComment.data += "foo", with selected range on detachedXmlComment from 1 to detachedXmlComment.length @@ -2967,9 +2967,9 @@ PASS detachedXmlComment.textContent = "", with selected range on detachedXmlComment from 1 to detachedXmlComment.length PASS detachedXmlComment.textContent = "foo", with unselected range on detachedXmlComment from 1 to detachedXmlComment.length PASS detachedXmlComment.textContent = "foo", with selected range on detachedXmlComment from 1 to detachedXmlComment.length -FAIL detachedXmlComment.textContent = detachedXmlComment.textContent, with unselected range on detachedXmlComment from 1 to detachedXmlComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlComment.textContent = detachedXmlComment.textContent, with unselected range on detachedXmlComment from 1 to detachedXmlComment.length PASS detachedXmlComment.textContent = detachedXmlComment.textContent, with selected range on detachedXmlComment from 1 to detachedXmlComment.length -FAIL detachedXmlComment.textContent += "", with unselected range on detachedXmlComment from 1 to detachedXmlComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlComment.textContent += "", with unselected range on detachedXmlComment from 1 to detachedXmlComment.length PASS detachedXmlComment.textContent += "", with selected range on detachedXmlComment from 1 to detachedXmlComment.length PASS detachedXmlComment.textContent += "foo", with unselected range on detachedXmlComment from 1 to detachedXmlComment.length PASS detachedXmlComment.textContent += "foo", with selected range on detachedXmlComment from 1 to detachedXmlComment.length @@ -2979,9 +2979,9 @@ PASS detachedXmlComment.nodeValue = "", with selected range on detachedXmlComment from 1 to detachedXmlComment.length PASS detachedXmlComment.nodeValue = "foo", with unselected range on detachedXmlComment from 1 to detachedXmlComment.length PASS detachedXmlComment.nodeValue = "foo", with selected range on detachedXmlComment from 1 to detachedXmlComment.length -FAIL detachedXmlComment.nodeValue = detachedXmlComment.nodeValue, with unselected range on detachedXmlComment from 1 to detachedXmlComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlComment.nodeValue = detachedXmlComment.nodeValue, with unselected range on detachedXmlComment from 1 to detachedXmlComment.length PASS detachedXmlComment.nodeValue = detachedXmlComment.nodeValue, with selected range on detachedXmlComment from 1 to detachedXmlComment.length -FAIL detachedXmlComment.nodeValue += "", with unselected range on detachedXmlComment from 1 to detachedXmlComment.length assert_equals: Wrong start offset expected 0 but got 1 +PASS detachedXmlComment.nodeValue += "", with unselected range on detachedXmlComment from 1 to detachedXmlComment.length PASS detachedXmlComment.nodeValue += "", with selected range on detachedXmlComment from 1 to detachedXmlComment.length PASS detachedXmlComment.nodeValue += "foo", with unselected range on detachedXmlComment from 1 to detachedXmlComment.length PASS detachedXmlComment.nodeValue += "foo", with selected range on detachedXmlComment from 1 to detachedXmlComment.length @@ -2991,9 +2991,9 @@ PASS detachedXmlComment.data = "", with selected range collapsed at (detachedXmlComment, detachedXmlComment.length) PASS detachedXmlComment.data = "foo", with unselected range collapsed at (detachedXmlComment, detachedXmlComment.length) PASS detachedXmlComment.data = "foo", with selected range collapsed at (detachedXmlComment, detachedXmlComment.length) -FAIL detachedXmlComment.data = detachedXmlComment.data, with unselected range collapsed at (detachedXmlComment, detachedXmlComment.length) assert_equals: Wrong start offset expected 0 but got 26 +PASS detachedXmlComment.data = detachedXmlComment.data, with unselected range collapsed at (detachedXmlComment, detachedXmlComment.length) PASS detachedXmlComment.data = detachedXmlComment.data, with selected range collapsed at (detachedXmlComment, detachedXmlComment.length) -FAIL detachedXmlComment.data += "", with unselected range collapsed at (detachedXmlComment, detachedXmlComment.length) assert_equals: Wrong start offset expected 0 but got 26 +PASS detachedXmlComment.data += "", with unselected range collapsed at (detachedXmlComment, detachedXmlComment.length) PASS detachedXmlComment.data += "", with selected range collapsed at (detachedXmlComment, detachedXmlComment.length) PASS detachedXmlComment.data += "foo", with unselected range collapsed at (detachedXmlComment, detachedXmlComment.length) PASS detachedXmlComment.data += "foo", with selected range collapsed at (detachedXmlComment, detachedXmlComment.length) @@ -3003,9 +3003,9 @@ PASS detachedXmlComment.textContent = "", with selected range collapsed at (detachedXmlComment, detachedXmlComment.length) PASS detachedXmlComment.textContent = "foo", with unselected range collapsed at (detachedXmlComment, detachedXmlComment.length) PASS detachedXmlComment.textContent = "foo", with selected range collapsed at (detachedXmlComment, detachedXmlComment.length) -FAIL detachedXmlComment.textContent = detachedXmlComment.textContent, with unselected range collapsed at (detachedXmlComment, detachedXmlComment.length) assert_equals: Wrong start offset expected 0 but got 26 +PASS detachedXmlComment.textContent = detachedXmlComment.textContent, with unselected range collapsed at (detachedXmlComment, detachedXmlComment.length) PASS detachedXmlComment.textContent = detachedXmlComment.textContent, with selected range collapsed at (detachedXmlComment, detachedXmlComment.length) -FAIL detachedXmlComment.textContent += "", with unselected range collapsed at (detachedXmlComment, detachedXmlComment.length) assert_equals: Wrong start offset expected 0 but got 26 +PASS detachedXmlComment.textContent += "", with unselected range collapsed at (detachedXmlComment, detachedXmlComment.length) PASS detachedXmlComment.textContent += "", with selected range collapsed at (detachedXmlComment, detachedXmlComment.length) PASS detachedXmlComment.textContent += "foo", with unselected range collapsed at (detachedXmlComment, detachedXmlComment.length) PASS detachedXmlComment.textContent += "foo", with selected range collapsed at (detachedXmlComment, detachedXmlComment.length) @@ -3015,9 +3015,9 @@ PASS detachedXmlComment.nodeValue = "", with selected range collapsed at (detachedXmlComment, detachedXmlComment.length) PASS detachedXmlComment.nodeValue = "foo", with unselected range collapsed at (detachedXmlComment, detachedXmlComment.length) PASS detachedXmlComment.nodeValue = "foo", with selected range collapsed at (detachedXmlComment, detachedXmlComment.length) -FAIL detachedXmlComment.nodeValue = detachedXmlComment.nodeValue, with unselected range collapsed at (detachedXmlComment, detachedXmlComment.length) assert_equals: Wrong start offset expected 0 but got 26 +PASS detachedXmlComment.nodeValue = detachedXmlComment.nodeValue, with unselected range collapsed at (detachedXmlComment, detachedXmlComment.length) PASS detachedXmlComment.nodeValue = detachedXmlComment.nodeValue, with selected range collapsed at (detachedXmlComment, detachedXmlComment.length) -FAIL detachedXmlComment.nodeValue += "", with unselected range collapsed at (detachedXmlComment, detachedXmlComment.length) assert_equals: Wrong start offset expected 0 but got 26 +PASS detachedXmlComment.nodeValue += "", with unselected range collapsed at (detachedXmlComment, detachedXmlComment.length) PASS detachedXmlComment.nodeValue += "", with selected range collapsed at (detachedXmlComment, detachedXmlComment.length) PASS detachedXmlComment.nodeValue += "foo", with unselected range collapsed at (detachedXmlComment, detachedXmlComment.length) PASS detachedXmlComment.nodeValue += "foo", with selected range collapsed at (detachedXmlComment, detachedXmlComment.length)
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/ranges/Range-mutations-insertBefore-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/ranges/Range-mutations-insertBefore-expected.txt deleted file mode 100644 index 4ca1f8b..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/dom/ranges/Range-mutations-insertBefore-expected.txt +++ /dev/null
@@ -1,91 +0,0 @@ -This is a testharness.js-based test. -FAIL testDiv.insertBefore(paras[0], paras[1]), with unselected range collapsed at (paras[0], 0) assert_equals: Wrong start container expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p><p id="b" s... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p> -FAIL testDiv.insertBefore(paras[0], paras[1]), with selected range collapsed at (paras[0], 0) assert_equals: Wrong start container expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p><p id="b" s... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p> -FAIL testDiv.insertBefore(paras[0], paras[1]), with unselected range on paras[0] from 0 to 1 assert_equals: Wrong start container expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p><p id="b" s... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p> -FAIL testDiv.insertBefore(paras[0], paras[1]), with selected range on paras[0] from 0 to 1 assert_equals: Wrong start container expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p><p id="b" s... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p> -FAIL testDiv.insertBefore(paras[0], paras[1]), with unselected range collapsed at (paras[0], 1) assert_equals: Wrong start container expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p><p id="b" s... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p> -FAIL testDiv.insertBefore(paras[0], paras[1]), with selected range collapsed at (paras[0], 1) assert_equals: Wrong start container expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p><p id="b" s... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p> -PASS testDiv.insertBefore(paras[0], paras[1]), with unselected range on testDiv from 0 to 2 -PASS testDiv.insertBefore(paras[0], paras[1]), with selected range on testDiv from 0 to 2 -FAIL testDiv.insertBefore(paras[0], paras[1]), with unselected range collapsed at (testDiv, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL testDiv.insertBefore(paras[0], paras[1]), with selected range collapsed at (testDiv, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL testDiv.insertBefore(paras[0], paras[1]), with unselected range on testDiv from 1 to 2 assert_equals: Wrong start offset expected 0 but got 1 -FAIL testDiv.insertBefore(paras[0], paras[1]), with selected range on testDiv from 1 to 2 assert_equals: Wrong start offset expected 0 but got 1 -PASS testDiv.insertBefore(paras[0], paras[1]), with unselected range collapsed at (testDiv, 2) -PASS testDiv.insertBefore(paras[0], paras[1]), with selected range collapsed at (testDiv, 2) -PASS paras[0].insertBefore(paras[1], paras[0].firstChild), with unselected range collapsed at (paras[0], 0) -PASS paras[0].insertBefore(paras[1], paras[0].firstChild), with selected range collapsed at (paras[0], 0) -PASS paras[0].insertBefore(paras[1], paras[0].firstChild), with unselected range on paras[0] from 0 to 1 -PASS paras[0].insertBefore(paras[1], paras[0].firstChild), with selected range on paras[0] from 0 to 1 -PASS paras[0].insertBefore(paras[1], paras[0].firstChild), with unselected range collapsed at (paras[0], 1) -PASS paras[0].insertBefore(paras[1], paras[0].firstChild), with selected range collapsed at (paras[0], 1) -PASS paras[0].insertBefore(paras[1], paras[0].firstChild), with unselected range on testDiv from 0 to 1 -PASS paras[0].insertBefore(paras[1], paras[0].firstChild), with selected range on testDiv from 0 to 1 -PASS paras[0].insertBefore(paras[1], paras[0].firstChild), with unselected range on testDiv from 0 to 2 -PASS paras[0].insertBefore(paras[1], paras[0].firstChild), with selected range on testDiv from 0 to 2 -PASS paras[0].insertBefore(paras[1], paras[0].firstChild), with unselected range collapsed at (testDiv, 1) -PASS paras[0].insertBefore(paras[1], paras[0].firstChild), with selected range collapsed at (testDiv, 1) -PASS paras[0].insertBefore(paras[1], paras[0].firstChild), with unselected range on testDiv from 1 to 2 -PASS paras[0].insertBefore(paras[1], paras[0].firstChild), with selected range on testDiv from 1 to 2 -PASS paras[0].insertBefore(paras[1], null), with unselected range collapsed at (paras[0], 0) -PASS paras[0].insertBefore(paras[1], null), with selected range collapsed at (paras[0], 0) -PASS paras[0].insertBefore(paras[1], null), with unselected range on paras[0] from 0 to 1 -PASS paras[0].insertBefore(paras[1], null), with selected range on paras[0] from 0 to 1 -PASS paras[0].insertBefore(paras[1], null), with unselected range collapsed at (paras[0], 1) -PASS paras[0].insertBefore(paras[1], null), with selected range collapsed at (paras[0], 1) -PASS paras[0].insertBefore(paras[1], null), with unselected range on testDiv from 0 to 1 -PASS paras[0].insertBefore(paras[1], null), with selected range on testDiv from 0 to 1 -PASS paras[0].insertBefore(paras[1], null), with unselected range on testDiv from 0 to 2 -PASS paras[0].insertBefore(paras[1], null), with selected range on testDiv from 0 to 2 -PASS paras[0].insertBefore(paras[1], null), with unselected range collapsed at (testDiv, 1) -PASS paras[0].insertBefore(paras[1], null), with selected range collapsed at (testDiv, 1) -PASS paras[0].insertBefore(paras[1], null), with unselected range on testDiv from 1 to 2 -PASS paras[0].insertBefore(paras[1], null), with selected range on testDiv from 1 to 2 -PASS foreignDoc.insertBefore(detachedComment, foreignDoc.documentElement), with unselected range collapsed at (foreignDoc, 0) -PASS foreignDoc.insertBefore(detachedComment, foreignDoc.documentElement), with selected range collapsed at (foreignDoc, 0) -PASS foreignDoc.insertBefore(detachedComment, foreignDoc.documentElement), with unselected range on foreignDoc from 0 to 1 -PASS foreignDoc.insertBefore(detachedComment, foreignDoc.documentElement), with selected range on foreignDoc from 0 to 1 -PASS foreignDoc.insertBefore(detachedComment, foreignDoc.documentElement), with unselected range on foreignDoc from 0 to 2 -PASS foreignDoc.insertBefore(detachedComment, foreignDoc.documentElement), with selected range on foreignDoc from 0 to 2 -PASS foreignDoc.insertBefore(detachedComment, foreignDoc.documentElement), with unselected range collapsed at (foreignDoc, 1) -PASS foreignDoc.insertBefore(detachedComment, foreignDoc.documentElement), with selected range collapsed at (foreignDoc, 1) -PASS foreignDoc.insertBefore(detachedComment, foreignDoc.doctype), with unselected range collapsed at (foreignDoc, 0) -PASS foreignDoc.insertBefore(detachedComment, foreignDoc.doctype), with selected range collapsed at (foreignDoc, 0) -PASS foreignDoc.insertBefore(detachedComment, foreignDoc.doctype), with unselected range on foreignDoc from 0 to 1 -PASS foreignDoc.insertBefore(detachedComment, foreignDoc.doctype), with selected range on foreignDoc from 0 to 1 -PASS foreignDoc.insertBefore(detachedComment, foreignDoc.doctype), with unselected range on foreignDoc from 0 to 2 -PASS foreignDoc.insertBefore(detachedComment, foreignDoc.doctype), with selected range on foreignDoc from 0 to 2 -PASS foreignDoc.insertBefore(detachedComment, foreignDoc.doctype), with unselected range collapsed at (foreignDoc, 1) -PASS foreignDoc.insertBefore(detachedComment, foreignDoc.doctype), with selected range collapsed at (foreignDoc, 1) -PASS foreignDoc.insertBefore(detachedComment, null), with unselected range on foreignDoc from 0 to 1 -PASS foreignDoc.insertBefore(detachedComment, null), with selected range on foreignDoc from 0 to 1 -PASS paras[0].insertBefore(xmlTextNode, paras[0].firstChild), with unselected range collapsed at (paras[0], 0) -PASS paras[0].insertBefore(xmlTextNode, paras[0].firstChild), with selected range collapsed at (paras[0], 0) -PASS paras[0].insertBefore(xmlTextNode, paras[0].firstChild), with unselected range on paras[0] from 0 to 1 -PASS paras[0].insertBefore(xmlTextNode, paras[0].firstChild), with selected range on paras[0] from 0 to 1 -PASS paras[0].insertBefore(xmlTextNode, paras[0].firstChild), with unselected range collapsed at (paras[0], 1) -PASS paras[0].insertBefore(xmlTextNode, paras[0].firstChild), with selected range collapsed at (paras[0], 1) -PASS paras[0].insertBefore(paras[0], paras[0].firstChild), with unselected range on paras[0] from 0 to 1 -PASS paras[0].insertBefore(paras[0], paras[0].firstChild), with selected range on paras[0] from 0 to 1 -PASS paras[0].insertBefore(testDiv, paras[0].firstChild), with unselected range on paras[0] from 0 to 1 -PASS paras[0].insertBefore(testDiv, paras[0].firstChild), with selected range on paras[0] from 0 to 1 -PASS paras[0].insertBefore(document, paras[0].firstChild), with unselected range on paras[0] from 0 to 1 -PASS paras[0].insertBefore(document, paras[0].firstChild), with selected range on paras[0] from 0 to 1 -PASS paras[0].insertBefore(foreignDoc, paras[0].firstChild), with unselected range on paras[0] from 0 to 1 -PASS paras[0].insertBefore(foreignDoc, paras[0].firstChild), with selected range on paras[0] from 0 to 1 -PASS paras[0].insertBefore(document.doctype, paras[0].firstChild), with unselected range on paras[0] from 0 to 1 -PASS paras[0].insertBefore(document.doctype, paras[0].firstChild), with selected range on paras[0] from 0 to 1 -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/ranges/Range-mutations-replaceChild-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/ranges/Range-mutations-replaceChild-expected.txt deleted file mode 100644 index 1c6b7a2e..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/dom/ranges/Range-mutations-replaceChild-expected.txt +++ /dev/null
@@ -1,75 +0,0 @@ -This is a testharness.js-based test. -FAIL testDiv.replaceChild(paras[0], paras[0]), with unselected range collapsed at (paras[0], 0) assert_equals: Wrong start container expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p><p id="b" s... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p> -FAIL testDiv.replaceChild(paras[0], paras[0]), with selected range collapsed at (paras[0], 0) assert_equals: Wrong start container expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p><p id="b" s... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p> -FAIL testDiv.replaceChild(paras[0], paras[0]), with unselected range on paras[0] from 0 to 1 assert_equals: Wrong start container expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p><p id="b" s... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p> -FAIL testDiv.replaceChild(paras[0], paras[0]), with selected range on paras[0] from 0 to 1 assert_equals: Wrong start container expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p><p id="b" s... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p> -FAIL testDiv.replaceChild(paras[0], paras[0]), with unselected range collapsed at (paras[0], 1) assert_equals: Wrong start container expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p><p id="b" s... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p> -FAIL testDiv.replaceChild(paras[0], paras[0]), with selected range collapsed at (paras[0], 1) assert_equals: Wrong start container expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p><p id="b" s... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ -</p> -PASS testDiv.replaceChild(paras[0], paras[0]), with unselected range on testDiv from 0 to 2 -PASS testDiv.replaceChild(paras[0], paras[0]), with selected range on testDiv from 0 to 2 -FAIL testDiv.replaceChild(paras[0], paras[0]), with unselected range collapsed at (testDiv, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL testDiv.replaceChild(paras[0], paras[0]), with selected range collapsed at (testDiv, 1) assert_equals: Wrong start offset expected 0 but got 1 -FAIL testDiv.replaceChild(paras[0], paras[0]), with unselected range on testDiv from 1 to 2 assert_equals: Wrong start offset expected 0 but got 1 -FAIL testDiv.replaceChild(paras[0], paras[0]), with selected range on testDiv from 1 to 2 assert_equals: Wrong start offset expected 0 but got 1 -PASS testDiv.replaceChild(paras[0], paras[0]), with unselected range collapsed at (testDiv, 2) -PASS testDiv.replaceChild(paras[0], paras[0]), with selected range collapsed at (testDiv, 2) -PASS paras[0].replaceChild(paras[1], paras[0].firstChild), with unselected range collapsed at (paras[0], 0) -PASS paras[0].replaceChild(paras[1], paras[0].firstChild), with selected range collapsed at (paras[0], 0) -PASS paras[0].replaceChild(paras[1], paras[0].firstChild), with unselected range on paras[0] from 0 to 1 -PASS paras[0].replaceChild(paras[1], paras[0].firstChild), with selected range on paras[0] from 0 to 1 -PASS paras[0].replaceChild(paras[1], paras[0].firstChild), with unselected range collapsed at (paras[0], 1) -PASS paras[0].replaceChild(paras[1], paras[0].firstChild), with selected range collapsed at (paras[0], 1) -PASS paras[0].replaceChild(paras[1], paras[0].firstChild), with unselected range on testDiv from 0 to 1 -PASS paras[0].replaceChild(paras[1], paras[0].firstChild), with selected range on testDiv from 0 to 1 -PASS paras[0].replaceChild(paras[1], paras[0].firstChild), with unselected range on testDiv from 0 to 2 -PASS paras[0].replaceChild(paras[1], paras[0].firstChild), with selected range on testDiv from 0 to 2 -PASS paras[0].replaceChild(paras[1], paras[0].firstChild), with unselected range collapsed at (testDiv, 1) -PASS paras[0].replaceChild(paras[1], paras[0].firstChild), with selected range collapsed at (testDiv, 1) -PASS paras[0].replaceChild(paras[1], paras[0].firstChild), with unselected range on testDiv from 1 to 2 -PASS paras[0].replaceChild(paras[1], paras[0].firstChild), with selected range on testDiv from 1 to 2 -PASS foreignDoc.replaceChild(detachedComment, foreignDoc.documentElement), with unselected range collapsed at (foreignDoc, 0) -PASS foreignDoc.replaceChild(detachedComment, foreignDoc.documentElement), with selected range collapsed at (foreignDoc, 0) -PASS foreignDoc.replaceChild(detachedComment, foreignDoc.documentElement), with unselected range on foreignDoc from 0 to 1 -PASS foreignDoc.replaceChild(detachedComment, foreignDoc.documentElement), with selected range on foreignDoc from 0 to 1 -PASS foreignDoc.replaceChild(detachedComment, foreignDoc.documentElement), with unselected range on foreignDoc from 0 to 2 -PASS foreignDoc.replaceChild(detachedComment, foreignDoc.documentElement), with selected range on foreignDoc from 0 to 2 -PASS foreignDoc.replaceChild(detachedComment, foreignDoc.documentElement), with unselected range collapsed at (foreignDoc, 1) -PASS foreignDoc.replaceChild(detachedComment, foreignDoc.documentElement), with selected range collapsed at (foreignDoc, 1) -PASS foreignDoc.replaceChild(detachedComment, foreignDoc.doctype), with unselected range collapsed at (foreignDoc, 0) -PASS foreignDoc.replaceChild(detachedComment, foreignDoc.doctype), with selected range collapsed at (foreignDoc, 0) -PASS foreignDoc.replaceChild(detachedComment, foreignDoc.doctype), with unselected range on foreignDoc from 0 to 1 -PASS foreignDoc.replaceChild(detachedComment, foreignDoc.doctype), with selected range on foreignDoc from 0 to 1 -PASS foreignDoc.replaceChild(detachedComment, foreignDoc.doctype), with unselected range on foreignDoc from 0 to 2 -PASS foreignDoc.replaceChild(detachedComment, foreignDoc.doctype), with selected range on foreignDoc from 0 to 2 -PASS foreignDoc.replaceChild(detachedComment, foreignDoc.doctype), with unselected range collapsed at (foreignDoc, 1) -PASS foreignDoc.replaceChild(detachedComment, foreignDoc.doctype), with selected range collapsed at (foreignDoc, 1) -PASS paras[0].replaceChild(xmlTextNode, paras[0].firstChild), with unselected range collapsed at (paras[0], 0) -PASS paras[0].replaceChild(xmlTextNode, paras[0].firstChild), with selected range collapsed at (paras[0], 0) -PASS paras[0].replaceChild(xmlTextNode, paras[0].firstChild), with unselected range on paras[0] from 0 to 1 -PASS paras[0].replaceChild(xmlTextNode, paras[0].firstChild), with selected range on paras[0] from 0 to 1 -PASS paras[0].replaceChild(xmlTextNode, paras[0].firstChild), with unselected range collapsed at (paras[0], 1) -PASS paras[0].replaceChild(xmlTextNode, paras[0].firstChild), with selected range collapsed at (paras[0], 1) -PASS paras[0].replaceChild(paras[0], paras[0].firstChild), with unselected range on paras[0] from 0 to 1 -PASS paras[0].replaceChild(paras[0], paras[0].firstChild), with selected range on paras[0] from 0 to 1 -PASS paras[0].replaceChild(testDiv, paras[0].firstChild), with unselected range on paras[0] from 0 to 1 -PASS paras[0].replaceChild(testDiv, paras[0].firstChild), with selected range on paras[0] from 0 to 1 -PASS paras[0].replaceChild(document, paras[0].firstChild), with unselected range on paras[0] from 0 to 1 -PASS paras[0].replaceChild(document, paras[0].firstChild), with selected range on paras[0] from 0 to 1 -PASS paras[0].replaceChild(foreignDoc, paras[0].firstChild), with unselected range on paras[0] from 0 to 1 -PASS paras[0].replaceChild(foreignDoc, paras[0].firstChild), with selected range on paras[0] from 0 to 1 -PASS paras[0].replaceChild(document.doctype, paras[0].firstChild), with unselected range on paras[0] from 0 to 1 -PASS paras[0].replaceChild(document.doctype, paras[0].firstChild), with selected range on paras[0] from 0 to 1 -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/read-media/pageload-image.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/read-media/pageload-image.html index 52151b8d..1f9c084 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/read-media/pageload-image.html +++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/read-media/pageload-image.html
@@ -13,6 +13,7 @@ function frameLoaded() { var testframe = document.getElementById('testframe'); + assert_equals(testframe.contentDocument.contentType, "image/png"); var testframeChildren = testframe.contentDocument.body.childNodes; assert_equals(testframeChildren.length, 1, "Body of image document has 1 child"); assert_equals(testframeChildren[0].nodeName, "IMG", "Only child of body must be an <img> element"); @@ -24,7 +25,6 @@ </head> <body> <div id="log"></div> - <iframe id="testframe" onload="t.step(frameLoaded)" - src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oMFgQGMyFwHucAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAADElEQVQI12P4//8/AAX+Av7czFnnAAAAAElFTkSuQmCC"></iframe> + <iframe id="testframe" onload="t.step(frameLoaded)" src="/images/blue.png"></iframe> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/read-media/pageload-video.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/read-media/pageload-video.html index 13bc5db4..69ef741 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/read-media/pageload-video.html +++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/browsing-the-web/read-media/pageload-video.html
@@ -13,6 +13,7 @@ function frameLoaded() { var testframe = document.getElementById('testframe'); + assert_equals(testframe.contentDocument.contentType, "video/webm"); var testframeChildren = testframe.contentDocument.body.childNodes; assert_equals(testframeChildren.length, 1, "Body of image document has 1 child"); assert_equals(testframeChildren[0].nodeName, "VIDEO", "Only child of body must be an <video> element"); @@ -24,7 +25,6 @@ </head> <body> <div id="log"></div> - <iframe id="testframe" onload="t.step(frameLoaded)" - src="data:video/webm,"></iframe> + <iframe id="testframe" onload="t.step(frameLoaded)" src="/media/white.webm"></iframe> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects-exceptions-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects-exceptions-expected.txt deleted file mode 100644 index 4af6e1e..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects-exceptions-expected.txt +++ /dev/null
@@ -1,21 +0,0 @@ -This is a testharness.js-based test. -FAIL Basic sanity-checking assert_equals: Need to run the top-level test from domain {{host}} expected "{{host}}" but got "" -FAIL Only whitelisted properties are accessible cross-origin assert_throws: Should throw when accessing stop on Window function "function () { C[prop]; }" did not throw -FAIL [[GetPrototypeOf]] should return null assert_true: cross-origin Window proto is null expected true got false -FAIL [[SetPrototypeOf]] should throw assert_throws: proto set on cross-origin Window function "function () { C.__proto__ = new Object(); }" threw object "TypeError: Immutable prototype object '#<Window>' cannot have their prototype set" that is not a DOMException SecurityError: property "code" is equal to undefined, expected 18 -PASS [[IsExtensible]] should return true for cross-origin objects -FAIL [[PreventExtensions]] should throw for cross-origin objects assert_throws: preventExtensions on cross-origin Window should throw function "function () { Object.preventExtensions(C) }" did not throw -PASS [[GetOwnProperty]] - Properties on cross-origin objects should be reported |own| -FAIL [[GetOwnProperty]] - Property descriptors for cross-origin properties should be set up correctly assert_equals: property descriptor for location should be non-enumerable expected false but got true -FAIL [[Delete]] Should throw on cross-origin objects assert_throws: Can't delete cross-origin indexed property function "function () { delete C[0]; }" did not throw -FAIL [[DefineOwnProperty]] Should throw for cross-origin objects assert_throws: Can't define cross-origin value property length function "function () { Object.defineProperty(obj, prop, valueDesc); }" did not throw -FAIL [[Enumerate]] should return an empty iterator assert_unreached: Shouldn't have been able to enumerate stop on cross-origin Window Reached unreachable code -FAIL [[OwnPropertyKeys]] should return all properties from cross-origin objects assert_array_equals: Object.getOwnPropertyNames() gives the right answer for cross-origin Window lengths differ, expected 877 got 13 -PASS A and B jointly observe the same identity for cross-origin Window and Location -PASS Cross-origin functions get local Function.prototype -FAIL Cross-origin Window accessors get local Function.prototype Cannot read property 'name' of undefined -FAIL Same-origin observers get different functions for cross-origin objects assert_true: same-origin Window functions get their own object expected true got false -FAIL Same-origin observers get different accessors for cross-origin Window assert_true: different Window accessors per-incumbent script settings object expected true got false -FAIL Same-origin observers get different accessors for cross-origin Location assert_true: different Location accessors per-incumbent script settings object expected true got false -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects-exceptions.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects-exceptions.html deleted file mode 100644 index 58c362a..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects-exceptions.html +++ /dev/null
@@ -1,333 +0,0 @@ -<!-- Once most browsers pass this test it can replace cross-origin-objects.html. It is meant to be - identical (please verify), except for also checking that the exceptions are correct. --> -<!doctype html> -<meta charset=utf-8> -<meta name="timeout" content="long"> -<title>Cross-origin behavior of Window and Location</title> -<link rel="author" title="Bobby Holley (:bholley)" href="bobbyholley@gmail.com"> -<link rel="help" href="https://html.spec.whatwg.org/multipage/#security-window"> -<link rel="help" href="https://html.spec.whatwg.org/multipage/#security-location"> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/common/get-host-info.sub.js"></script> -<div id=log></div> -<iframe id="B"></iframe> -<iframe id="C"></iframe> -<script> -/* - * Setup boilerplate. This gives us a same-origin window "B" and a cross-origin - * window "C". - */ -var host_info = get_host_info(); - -setup({explicit_done: true}); -path = location.pathname.substring(0, location.pathname.lastIndexOf('/')) + '/frame.html'; -var B = document.getElementById('B').contentWindow; -var C = document.getElementById('C').contentWindow; -B.frameElement.uriToLoad = path; -C.frameElement.uriToLoad = get_host_info().HTTP_REMOTE_ORIGIN + path; - -function reloadSubframes(cb) { - var iframes = document.getElementsByTagName('iframe'); - iframes.forEach = Array.prototype.forEach; - var count = 0; - function frameLoaded() { - this.onload = null; - if (++count == iframes.length) - cb(); - } - iframes.forEach(function(ifr) { ifr.onload = frameLoaded; ifr.setAttribute('src', ifr.uriToLoad); }); -} -function isObject(x) { return Object(x) === x; } - -/* - * Note: we eschew assert_equals in a lot of these tests, since the harness ends - * up throwing when it tries to format a message involving a cross-origin object. - */ - -var testList = []; -function addTest(fun, desc) { testList.push([fun, desc]); } - - -/* - * Basic sanity testing. - */ - -addTest(function() { - // Note: we do not check location.host as its default port semantics are hard to reflect statically - assert_equals(location.hostname, host_info.ORIGINAL_HOST, 'Need to run the top-level test from domain ' + host_info.ORIGINAL_HOST); - assert_equals(get_port(location), host_info.HTTP_PORT, 'Need to run the top-level test from port ' + host_info.HTTP_PORT); - assert_equals(B.parent, window, "window.parent works same-origin"); - assert_equals(C.parent, window, "window.parent works cross-origin"); - assert_equals(B.location.pathname, path, "location.href works same-origin"); - assert_throws("SecurityError", function() { C.location.pathname; }, "location.pathname throws cross-origin"); - assert_equals(B.frames, 'override', "Overrides visible in the same-origin case"); - assert_equals(C.frames, C, "Overrides invisible in the cross-origin case"); -}, "Basic sanity-checking"); - -/* - * Whitelist behavior. - * - * Also tests for [[GetOwnProperty]] and [[HasOwnProperty]] behavior. - */ - -var whitelistedWindowIndices = ['0', '1']; -var whitelistedWindowProps = ['location', 'postMessage', 'window', 'frames', 'self', 'top', 'parent', - 'opener', 'closed', 'close', 'blur', 'focus', 'length']; -whitelistedWindowProps = whitelistedWindowProps.concat(whitelistedWindowIndices); -whitelistedWindowProps.sort(); - -addTest(function() { - for (var prop in window) { - if (whitelistedWindowProps.indexOf(prop) != -1) { - C[prop]; // Shouldn't throw. - Object.getOwnPropertyDescriptor(C, prop); // Shouldn't throw. - assert_true(Object.prototype.hasOwnProperty.call(C, prop), "hasOwnProperty for " + prop); - } else { - assert_throws("SecurityError", function() { C[prop]; }, "Should throw when accessing " + prop + " on Window"); - assert_throws("SecurityError", function() { Object.getOwnPropertyDescriptor(C, prop); }, - "Should throw when accessing property descriptor for " + prop + " on Window"); - assert_throws("SecurityError", function() { Object.prototype.hasOwnProperty.call(C, prop); }, - "Should throw when invoking hasOwnProperty for " + prop + " on Window"); - } - if (prop != 'location') - assert_throws("SecurityError", function() { C[prop] = undefined; }, "Should throw when writing to " + prop + " on Window"); - } - for (var prop in location) { - if (prop == 'replace') { - C.location[prop]; // Shouldn't throw. - Object.getOwnPropertyDescriptor(C.location, prop); // Shouldn't throw. - assert_true(Object.prototype.hasOwnProperty.call(C.location, prop), "hasOwnProperty for " + prop); - } - else { - assert_throws("SecurityError", function() { C[prop]; }, "Should throw when accessing " + prop + " on Location"); - assert_throws("SecurityError", function() { Object.getOwnPropertyDescriptor(C, prop); }, - "Should throw when accessing property descriptor for " + prop + " on Location"); - assert_throws("SecurityError", function() { Object.prototype.hasOwnProperty.call(C, prop); }, - "Should throw when invoking hasOwnProperty for " + prop + " on Location"); - } - if (prop != 'href') - assert_throws("SecurityError", function() { C[prop] = undefined; }, "Should throw when writing to " + prop + " on Location"); - } -}, "Only whitelisted properties are accessible cross-origin"); - -/* - * ES Internal Methods. - */ - -/* - * [[GetPrototypeOf]] - */ -addTest(function() { - assert_true(Object.getPrototypeOf(C) === null, "cross-origin Window proto is null"); - assert_true(Object.getPrototypeOf(C.location) === null, "cross-origin Location proto is null (__proto__)"); - var protoGetter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').get; - assert_true(protoGetter.call(C) === null, "cross-origin Window proto is null"); - assert_true(protoGetter.call(C.location) === null, "cross-origin Location proto is null (__proto__)"); - assert_throws("SecurityError", function() { C.__proto__; }, "__proto__ property not available cross-origin"); - assert_throws("SecurityError", function() { C.location.__proto__; }, "__proto__ property not available cross-origin"); - -}, "[[GetPrototypeOf]] should return null"); - -/* - * [[SetPrototypeOf]] - */ -addTest(function() { - assert_throws("SecurityError", function() { C.__proto__ = new Object(); }, "proto set on cross-origin Window"); - assert_throws("SecurityError", function() { C.location.__proto__ = new Object(); }, "proto set on cross-origin Location"); - var setters = [Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set]; - if (Object.setPrototypeOf) - setters.push(function(p) { Object.setPrototypeOf(this, p); }); - setters.forEach(function(protoSetter) { - assert_throws(new TypeError, function() { protoSetter.call(C, new Object()); }, "proto setter |call| on cross-origin Window"); - assert_throws(new TypeError, function() { protoSetter.call(C.location, new Object()); }, "proto setter |call| on cross-origin Location"); - }); -}, "[[SetPrototypeOf]] should throw"); - -/* - * [[IsExtensible]] - */ -addTest(function() { - assert_true(Object.isExtensible(C), "cross-origin Window should be extensible"); - assert_true(Object.isExtensible(C.location), "cross-origin Location should be extensible"); -}, "[[IsExtensible]] should return true for cross-origin objects"); - -/* - * [[PreventExtensions]] - */ -addTest(function() { - assert_throws(new TypeError, function() { Object.preventExtensions(C) }, - "preventExtensions on cross-origin Window should throw"); - assert_throws(new TypeError, function() { Object.preventExtensions(C.location) }, - "preventExtensions on cross-origin Location should throw"); -}, "[[PreventExtensions]] should throw for cross-origin objects"); - -/* - * [[GetOwnProperty]] - */ - -addTest(function() { - assert_true(isObject(Object.getOwnPropertyDescriptor(C, 'close')), "C.close is |own|"); - assert_true(isObject(Object.getOwnPropertyDescriptor(C, 'top')), "C.top is |own|"); - assert_true(isObject(Object.getOwnPropertyDescriptor(C.location, 'href')), "C.location.href is |own|"); - assert_true(isObject(Object.getOwnPropertyDescriptor(C.location, 'replace')), "C.location.replace is |own|"); -}, "[[GetOwnProperty]] - Properties on cross-origin objects should be reported |own|"); - -function checkPropertyDescriptor(desc, propName, expectWritable) { - assert_true(isObject(desc), "property descriptor for " + propName + " should exist"); - assert_equals(desc.enumerable, false, "property descriptor for " + propName + " should be non-enumerable"); - assert_equals(desc.configurable, true, "property descriptor for " + propName + " should be configurable"); - if ('value' in desc) - assert_equals(desc.writable, expectWritable, "property descriptor for " + propName + " should have writable: " + expectWritable); - else - assert_equals(typeof desc.set != 'undefined', expectWritable, - "property descriptor for " + propName + " should " + (expectWritable ? "" : "not ") + "have setter"); -} - -addTest(function() { - whitelistedWindowProps.forEach(function(prop) { - var desc = Object.getOwnPropertyDescriptor(C, prop); - checkPropertyDescriptor(desc, prop, prop == 'location'); - }); - checkPropertyDescriptor(Object.getOwnPropertyDescriptor(C.location, 'replace'), 'replace', false); - checkPropertyDescriptor(Object.getOwnPropertyDescriptor(C.location, 'href'), 'href', true); - assert_equals(typeof Object.getOwnPropertyDescriptor(C.location, 'href').get, 'undefined', "Cross-origin location should have no href getter"); -}, "[[GetOwnProperty]] - Property descriptors for cross-origin properties should be set up correctly"); - -/* - * [[Delete]] - */ -addTest(function() { - assert_throws("SecurityError", function() { delete C[0]; }, "Can't delete cross-origin indexed property"); - assert_throws("SecurityError", function() { delete C[100]; }, "Can't delete cross-origin indexed property"); - assert_throws("SecurityError", function() { delete C.location; }, "Can't delete cross-origin property"); - assert_throws("SecurityError", function() { delete C.parent; }, "Can't delete cross-origin property"); - assert_throws("SecurityError", function() { delete C.length; }, "Can't delete cross-origin property"); - assert_throws("SecurityError", function() { delete C.document; }, "Can't delete cross-origin property"); - assert_throws("SecurityError", function() { delete C.foopy; }, "Can't delete cross-origin property"); - assert_throws("SecurityError", function() { delete C.location.href; }, "Can't delete cross-origin property"); - assert_throws("SecurityError", function() { delete C.location.replace; }, "Can't delete cross-origin property"); - assert_throws("SecurityError", function() { delete C.location.port; }, "Can't delete cross-origin property"); - assert_throws("SecurityError", function() { delete C.location.foopy; }, "Can't delete cross-origin property"); -}, "[[Delete]] Should throw on cross-origin objects"); - -/* - * [[DefineOwnProperty]] - */ -function checkDefine(obj, prop) { - var valueDesc = { configurable: true, enumerable: false, writable: false, value: 2 }; - var accessorDesc = { configurable: true, enumerable: false, get: function() {} }; - assert_throws("SecurityError", function() { Object.defineProperty(obj, prop, valueDesc); }, "Can't define cross-origin value property " + prop); - assert_throws("SecurityError", function() { Object.defineProperty(obj, prop, accessorDesc); }, "Can't define cross-origin accessor property " + prop); -} -addTest(function() { - checkDefine(C, 'length'); - checkDefine(C, 'parent'); - checkDefine(C, 'location'); - checkDefine(C, 'document'); - checkDefine(C, 'foopy'); - checkDefine(C.location, 'href'); - checkDefine(C.location, 'replace'); - checkDefine(C.location, 'port'); - checkDefine(C.location, 'foopy'); -}, "[[DefineOwnProperty]] Should throw for cross-origin objects"); - -/* - * [[Enumerate]] - */ - -addTest(function() { - for (var prop in C) - assert_unreached("Shouldn't have been able to enumerate " + prop + " on cross-origin Window"); - for (var prop in C.location) - assert_unreached("Shouldn't have been able to enumerate " + prop + " on cross-origin Location"); -}, "[[Enumerate]] should return an empty iterator"); - -/* - * [[OwnPropertyKeys]] - */ - -addTest(function() { - assert_array_equals(Object.getOwnPropertyNames(C).sort(), whitelistedWindowProps.sort(), - "Object.getOwnPropertyNames() gives the right answer for cross-origin Window"); - assert_array_equals(Object.getOwnPropertyNames(C.location).sort(), ['href', 'replace'], - "Object.getOwnPropertyNames() gives the right answer for cross-origin Location"); -}, "[[OwnPropertyKeys]] should return all properties from cross-origin objects"); - -addTest(function() { - assert_true(B.eval('parent.C') === C, "A and B observe the same identity for C's Window"); - assert_true(B.eval('parent.C.location') === C.location, "A and B observe the same identity for C's Location"); -}, "A and B jointly observe the same identity for cross-origin Window and Location"); - -function checkFunction(f, proto) { - var name = f.name || '<missing name>'; - assert_equals(typeof f, 'function', name + " is a function"); - assert_equals(Object.getPrototypeOf(f), proto, f.name + " has the right prototype"); -} - -addTest(function() { - checkFunction(C.close, Function.prototype); - checkFunction(C.location.replace, Function.prototype); -}, "Cross-origin functions get local Function.prototype"); - -addTest(function() { - assert_true(isObject(Object.getOwnPropertyDescriptor(C, 'parent')), - "Need to be able to use Object.getOwnPropertyDescriptor do this test"); - checkFunction(Object.getOwnPropertyDescriptor(C, 'parent').get, Function.prototype); - checkFunction(Object.getOwnPropertyDescriptor(C.location, 'href').set, Function.prototype); -}, "Cross-origin Window accessors get local Function.prototype"); - -addTest(function() { - checkFunction(close, Function.prototype); - assert_true(close != B.close, 'same-origin Window functions get their own object'); - assert_true(close != C.close, 'cross-origin Window functions get their own object'); - var close_B = B.eval('parent.C.close'); - assert_true(close != close_B, 'close_B is unique when viewed by the parent'); - assert_true(close_B != C.close, 'different Window functions per-incumbent script settings object'); - checkFunction(close_B, B.Function.prototype); - - checkFunction(location.replace, Function.prototype); - assert_true(location.replace != C.location.replace, "cross-origin Location functions get their own object"); - var replace_B = B.eval('parent.C.location.replace'); - assert_true(replace_B != C.location.replace, 'different Location functions per-incumbent script settings object'); - checkFunction(replace_B, B.Function.prototype); -}, "Same-origin observers get different functions for cross-origin objects"); - -addTest(function() { - assert_true(isObject(Object.getOwnPropertyDescriptor(C, 'parent')), - "Need to be able to use Object.getOwnPropertyDescriptor do this test"); - var get_self_parent = Object.getOwnPropertyDescriptor(window, 'parent').get; - var get_parent_A = Object.getOwnPropertyDescriptor(C, 'parent').get; - var get_parent_B = B.eval('Object.getOwnPropertyDescriptor(parent.C, "parent").get'); - assert_true(get_self_parent != get_parent_A, 'different Window accessors per-incumbent script settings object'); - assert_true(get_parent_A != get_parent_B, 'different Window accessors per-incumbent script settings object'); - checkFunction(get_self_parent, Function.prototype); - checkFunction(get_parent_A, Function.prototype); - checkFunction(get_parent_B, B.Function.prototype); -}, "Same-origin observers get different accessors for cross-origin Window"); - -addTest(function() { - var set_self_href = Object.getOwnPropertyDescriptor(window.location, 'href').set; - var set_href_A = Object.getOwnPropertyDescriptor(C.location, 'href').set; - var set_href_B = B.eval('Object.getOwnPropertyDescriptor(parent.C.location, "href").set'); - assert_true(set_self_href != set_href_A, 'different Location accessors per-incumbent script settings object'); - assert_true(set_href_A != set_href_B, 'different Location accessors per-incumbent script settings object'); - checkFunction(set_self_href, Function.prototype); - checkFunction(set_href_A, Function.prototype); - checkFunction(set_href_B, B.Function.prototype); -}, "Same-origin observers get different accessors for cross-origin Location"); - -// We do a fresh load of the subframes for each test to minimize side-effects. -// It would be nice to reload ourselves as well, but we can't do that without -// disrupting the test harness. -function runNextTest() { - var entry = testList.shift(); - test(entry[0], entry[1]); - if (testList.length != 0) - reloadSubframes(runNextTest); - else - done(); -} -reloadSubframes(runNextTest); - -</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html index 7560fcd..7ffd474 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html +++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html
@@ -52,14 +52,14 @@ * Basic sanity testing. */ -addTest(function() { +addTest(function(exception_t) { // Note: we do not check location.host as its default port semantics are hard to reflect statically assert_equals(location.hostname, host_info.ORIGINAL_HOST, 'Need to run the top-level test from domain ' + host_info.ORIGINAL_HOST); assert_equals(get_port(location), host_info.HTTP_PORT, 'Need to run the top-level test from port ' + host_info.HTTP_PORT); assert_equals(B.parent, window, "window.parent works same-origin"); assert_equals(C.parent, window, "window.parent works cross-origin"); assert_equals(B.location.pathname, path, "location.href works same-origin"); - assert_throws(null, function() { C.location.pathname; }, "location.pathname throws cross-origin"); + test_throws(exception_t, "SecurityError", function() { C.location.pathname; }, "location.pathname throws cross-origin"); assert_equals(B.frames, 'override', "Overrides visible in the same-origin case"); assert_equals(C.frames, C, "Overrides invisible in the cross-origin case"); }, "Basic sanity-checking"); @@ -81,21 +81,21 @@ Symbol.isConcatSpreadable]; var whitelistedWindowProps = whitelistedWindowPropNames.concat(whitelistedSymbols); -addTest(function() { +addTest(function(exception_t) { for (var prop in window) { if (whitelistedWindowProps.indexOf(prop) != -1) { C[prop]; // Shouldn't throw. Object.getOwnPropertyDescriptor(C, prop); // Shouldn't throw. assert_true(Object.prototype.hasOwnProperty.call(C, prop), "hasOwnProperty for " + String(prop)); } else { - assert_throws(null, function() { C[prop]; }, "Should throw when accessing " + String(prop) + " on Window"); - assert_throws(null, function() { Object.getOwnPropertyDescriptor(C, prop); }, + test_throws(exception_t, "SecurityError", function() { C[prop]; }, "Should throw when accessing " + String(prop) + " on Window"); + test_throws(exception_t, "SecurityError", function() { Object.getOwnPropertyDescriptor(C, prop); }, "Should throw when accessing property descriptor for " + prop + " on Window"); - assert_throws(null, function() { Object.prototype.hasOwnProperty.call(C, prop); }, + test_throws(exception_t, "SecurityError", function() { Object.prototype.hasOwnProperty.call(C, prop); }, "Should throw when invoking hasOwnProperty for " + prop + " on Window"); } if (prop != 'location') - assert_throws(null, function() { C[prop] = undefined; }, "Should throw when writing to " + prop + " on Window"); + test_throws(exception_t, "SecurityError", function() { C[prop] = undefined; }, "Should throw when writing to " + prop + " on Window"); } for (var prop in location) { if (prop == 'replace') { @@ -104,14 +104,14 @@ assert_true(Object.prototype.hasOwnProperty.call(C.location, prop), "hasOwnProperty for " + prop); } else { - assert_throws(null, function() { C[prop]; }, "Should throw when accessing " + prop + " on Location"); - assert_throws(null, function() { Object.getOwnPropertyDescriptor(C, prop); }, + test_throws(exception_t, "SecurityError", function() { C[prop]; }, "Should throw when accessing " + prop + " on Location"); + test_throws(exception_t, "SecurityError", function() { Object.getOwnPropertyDescriptor(C, prop); }, "Should throw when accessing property descriptor for " + prop + " on Location"); - assert_throws(null, function() { Object.prototype.hasOwnProperty.call(C, prop); }, + test_throws(exception_t, "SecurityError", function() { Object.prototype.hasOwnProperty.call(C, prop); }, "Should throw when invoking hasOwnProperty for " + prop + " on Location"); } if (prop != 'href') - assert_throws(null, function() { C[prop] = undefined; }, "Should throw when writing to " + prop + " on Location"); + test_throws(exception_t, "SecurityError", function() { C[prop] = undefined; }, "Should throw when writing to " + prop + " on Location"); } }, "Only whitelisted properties are accessible cross-origin"); @@ -122,36 +122,36 @@ /* * [[GetPrototypeOf]] */ -addTest(function() { +addTest(function(exception_t) { assert_true(Object.getPrototypeOf(C) === null, "cross-origin Window proto is null"); assert_true(Object.getPrototypeOf(C.location) === null, "cross-origin Location proto is null (__proto__)"); var protoGetter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').get; assert_true(protoGetter.call(C) === null, "cross-origin Window proto is null"); assert_true(protoGetter.call(C.location) === null, "cross-origin Location proto is null (__proto__)"); - assert_throws(null, function() { C.__proto__; }, "__proto__ property not available cross-origin"); - assert_throws(null, function() { C.location.__proto__; }, "__proto__ property not available cross-origin"); + test_throws(exception_t, "SecurityError", function() { C.__proto__; }, "__proto__ property not available cross-origin"); + test_throws(exception_t, "SecurityError", function() { C.location.__proto__; }, "__proto__ property not available cross-origin"); }, "[[GetPrototypeOf]] should return null"); /* * [[SetPrototypeOf]] */ -addTest(function() { - assert_throws(null, function() { C.__proto__ = new Object(); }, "proto set on cross-origin Window"); - assert_throws(null, function() { C.location.__proto__ = new Object(); }, "proto set on cross-origin Location"); +addTest(function(exception_t) { + test_throws(exception_t, "SecurityError", function() { C.__proto__ = new Object(); }, "proto set on cross-origin Window"); + test_throws(exception_t, "SecurityError", function() { C.location.__proto__ = new Object(); }, "proto set on cross-origin Location"); var setters = [Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set]; if (Object.setPrototypeOf) setters.push(function(p) { Object.setPrototypeOf(this, p); }); setters.forEach(function(protoSetter) { - assert_throws(null, function() { protoSetter.call(C, new Object()); }, "proto setter |call| on cross-origin Window"); - assert_throws(null, function() { protoSetter.call(C.location, new Object()); }, "proto setter |call| on cross-origin Location"); + test_throws(exception_t, new TypeError, function() { protoSetter.call(C, new Object()); }, "proto setter |call| on cross-origin Window"); + test_throws(exception_t, new TypeError, function() { protoSetter.call(C.location, new Object()); }, "proto setter |call| on cross-origin Location"); }); }, "[[SetPrototypeOf]] should throw"); /* * [[IsExtensible]] */ -addTest(function() { +addTest(function(exception_t) { assert_true(Object.isExtensible(C), "cross-origin Window should be extensible"); assert_true(Object.isExtensible(C.location), "cross-origin Location should be extensible"); }, "[[IsExtensible]] should return true for cross-origin objects"); @@ -159,10 +159,10 @@ /* * [[PreventExtensions]] */ -addTest(function() { - assert_throws(null, function() { Object.preventExtensions(C) }, +addTest(function(exception_t) { + test_throws(exception_t, new TypeError, function() { Object.preventExtensions(C) }, "preventExtensions on cross-origin Window should throw"); - assert_throws(null, function() { Object.preventExtensions(C.location) }, + test_throws(exception_t, new TypeError, function() { Object.preventExtensions(C.location) }, "preventExtensions on cross-origin Location should throw"); }, "[[PreventExtensions]] should throw for cross-origin objects"); @@ -170,7 +170,7 @@ * [[GetOwnProperty]] */ -addTest(function() { +addTest(function(exception_t) { assert_true(isObject(Object.getOwnPropertyDescriptor(C, 'close')), "C.close is |own|"); assert_true(isObject(Object.getOwnPropertyDescriptor(C, 'top')), "C.top is |own|"); assert_true(isObject(Object.getOwnPropertyDescriptor(C.location, 'href')), "C.location.href is |own|"); @@ -197,7 +197,7 @@ "property descriptor for " + propName + " should " + (expectWritable ? "" : "not ") + "have setter"); } -addTest(function() { +addTest(function(exception_t) { whitelistedWindowProps.forEach(function(prop) { var desc = Object.getOwnPropertyDescriptor(C, prop); checkPropertyDescriptor(desc, prop, prop == 'location'); @@ -214,46 +214,46 @@ /* * [[Delete]] */ -addTest(function() { - assert_throws(null, function() { delete C[0]; }, "Can't delete cross-origin indexed property"); - assert_throws(null, function() { delete C[100]; }, "Can't delete cross-origin indexed property"); - assert_throws(null, function() { delete C.location; }, "Can't delete cross-origin property"); - assert_throws(null, function() { delete C.parent; }, "Can't delete cross-origin property"); - assert_throws(null, function() { delete C.length; }, "Can't delete cross-origin property"); - assert_throws(null, function() { delete C.document; }, "Can't delete cross-origin property"); - assert_throws(null, function() { delete C.foopy; }, "Can't delete cross-origin property"); - assert_throws(null, function() { delete C.location.href; }, "Can't delete cross-origin property"); - assert_throws(null, function() { delete C.location.replace; }, "Can't delete cross-origin property"); - assert_throws(null, function() { delete C.location.port; }, "Can't delete cross-origin property"); - assert_throws(null, function() { delete C.location.foopy; }, "Can't delete cross-origin property"); +addTest(function(exception_t) { + test_throws(exception_t, "SecurityError", function() { delete C[0]; }, "Can't delete cross-origin indexed property"); + test_throws(exception_t, "SecurityError", function() { delete C[100]; }, "Can't delete cross-origin indexed property"); + test_throws(exception_t, "SecurityError", function() { delete C.location; }, "Can't delete cross-origin property"); + test_throws(exception_t, "SecurityError", function() { delete C.parent; }, "Can't delete cross-origin property"); + test_throws(exception_t, "SecurityError", function() { delete C.length; }, "Can't delete cross-origin property"); + test_throws(exception_t, "SecurityError", function() { delete C.document; }, "Can't delete cross-origin property"); + test_throws(exception_t, "SecurityError", function() { delete C.foopy; }, "Can't delete cross-origin property"); + test_throws(exception_t, "SecurityError", function() { delete C.location.href; }, "Can't delete cross-origin property"); + test_throws(exception_t, "SecurityError", function() { delete C.location.replace; }, "Can't delete cross-origin property"); + test_throws(exception_t, "SecurityError", function() { delete C.location.port; }, "Can't delete cross-origin property"); + test_throws(exception_t, "SecurityError", function() { delete C.location.foopy; }, "Can't delete cross-origin property"); }, "[[Delete]] Should throw on cross-origin objects"); /* * [[DefineOwnProperty]] */ -function checkDefine(obj, prop) { +function checkDefine(exception_t, obj, prop) { var valueDesc = { configurable: true, enumerable: false, writable: false, value: 2 }; var accessorDesc = { configurable: true, enumerable: false, get: function() {} }; - assert_throws(null, function() { Object.defineProperty(obj, prop, valueDesc); }, "Can't define cross-origin value property " + prop); - assert_throws(null, function() { Object.defineProperty(obj, prop, accessorDesc); }, "Can't define cross-origin accessor property " + prop); + test_throws(exception_t, "SecurityError", function() { Object.defineProperty(obj, prop, valueDesc); }, "Can't define cross-origin value property " + prop); + test_throws(exception_t, "SecurityError", function() { Object.defineProperty(obj, prop, accessorDesc); }, "Can't define cross-origin accessor property " + prop); } -addTest(function() { - checkDefine(C, 'length'); - checkDefine(C, 'parent'); - checkDefine(C, 'location'); - checkDefine(C, 'document'); - checkDefine(C, 'foopy'); - checkDefine(C.location, 'href'); - checkDefine(C.location, 'replace'); - checkDefine(C.location, 'port'); - checkDefine(C.location, 'foopy'); +addTest(function(exception_t) { + checkDefine(exception_t, C, 'length'); + checkDefine(exception_t, C, 'parent'); + checkDefine(exception_t, C, 'location'); + checkDefine(exception_t, C, 'document'); + checkDefine(exception_t, C, 'foopy'); + checkDefine(exception_t, C.location, 'href'); + checkDefine(exception_t, C.location, 'replace'); + checkDefine(exception_t, C.location, 'port'); + checkDefine(exception_t, C.location, 'foopy'); }, "[[DefineOwnProperty]] Should throw for cross-origin objects"); /* * [[Enumerate]] */ -addTest(function() { +addTest(function(exception_t) { for (var prop in C) assert_unreached("Shouldn't have been able to enumerate " + prop + " on cross-origin Window"); for (var prop in C.location) @@ -264,7 +264,7 @@ * [[OwnPropertyKeys]] */ -addTest(function() { +addTest(function(exception_t) { assert_array_equals(Object.getOwnPropertyNames(C).sort(), whitelistedWindowPropNames, "Object.getOwnPropertyNames() gives the right answer for cross-origin Window"); @@ -273,7 +273,7 @@ "Object.getOwnPropertyNames() gives the right answer for cross-origin Location"); }, "[[OwnPropertyKeys]] should return all properties from cross-origin objects"); -addTest(function() { +addTest(function(exception_t) { assert_array_equals(Object.getOwnPropertySymbols(C), whitelistedSymbols, "Object.getOwnPropertySymbols() should return the three symbol-named properties that are exposed on a cross-origin Window"); assert_array_equals(Object.getOwnPropertySymbols(C.location), @@ -281,7 +281,7 @@ "Object.getOwnPropertySymbols() should return the three symbol-named properties that are exposed on a cross-origin Location"); }, "[[OwnPropertyKeys]] should return the right symbol-named properties for cross-origin objects"); -addTest(function() { +addTest(function(exception_t) { var allWindowProps = Reflect.ownKeys(C); indexedWindowProps = allWindowProps.slice(0, whitelistedWindowIndices.length); stringWindowProps = allWindowProps.slice(0, -1 * whitelistedSymbols.length); @@ -302,7 +302,7 @@ "Reflect.ownKeys should end with the cross-origin symbols for a cross-origin Location.") }, "[[OwnPropertyKeys]] should place the symbols after the property names after the subframe indices"); -addTest(function() { +addTest(function(exception_t) { assert_true(B.eval('parent.C') === C, "A and B observe the same identity for C's Window"); assert_true(B.eval('parent.C.location') === C.location, "A and B observe the same identity for C's Location"); }, "A and B jointly observe the same identity for cross-origin Window and Location"); @@ -313,19 +313,19 @@ assert_equals(Object.getPrototypeOf(f), proto, f.name + " has the right prototype"); } -addTest(function() { +addTest(function(exception_t) { checkFunction(C.close, Function.prototype); checkFunction(C.location.replace, Function.prototype); }, "Cross-origin functions get local Function.prototype"); -addTest(function() { +addTest(function(exception_t) { assert_true(isObject(Object.getOwnPropertyDescriptor(C, 'parent')), "Need to be able to use Object.getOwnPropertyDescriptor do this test"); checkFunction(Object.getOwnPropertyDescriptor(C, 'parent').get, Function.prototype); checkFunction(Object.getOwnPropertyDescriptor(C.location, 'href').set, Function.prototype); }, "Cross-origin Window accessors get local Function.prototype"); -addTest(function() { +addTest(function(exception_t) { checkFunction(close, Function.prototype); assert_true(close != B.close, 'same-origin Window functions get their own object'); assert_true(close != C.close, 'cross-origin Window functions get their own object'); @@ -341,7 +341,7 @@ checkFunction(replace_B, B.Function.prototype); }, "Same-origin observers get different functions for cross-origin objects"); -addTest(function() { +addTest(function(exception_t) { assert_true(isObject(Object.getOwnPropertyDescriptor(C, 'parent')), "Need to be able to use Object.getOwnPropertyDescriptor do this test"); var get_self_parent = Object.getOwnPropertyDescriptor(window, 'parent').get; @@ -354,7 +354,7 @@ checkFunction(get_parent_B, B.Function.prototype); }, "Same-origin observers get different accessors for cross-origin Window"); -addTest(function() { +addTest(function(exception_t) { var set_self_href = Object.getOwnPropertyDescriptor(window.location, 'href').set; var set_href_A = Object.getOwnPropertyDescriptor(C.location, 'href').set; var set_href_B = B.eval('Object.getOwnPropertyDescriptor(parent.C.location, "href").set'); @@ -365,17 +365,39 @@ checkFunction(set_href_B, B.Function.prototype); }, "Same-origin observers get different accessors for cross-origin Location"); -addTest(function() { +addTest(function(exception_t) { assert_equals({}.toString.call(C), "[object Object]"); assert_equals({}.toString.call(C.location), "[object Object]"); }, "{}.toString.call() does the right thing on cross-origin objects"); +// Separate test for throwing at all and throwing the right exception type +// so that we can test that all implementations could pass while implementing +// the observables that are actually important for security and interop, so +// they would notice if they ever regressed them. +function test_throws(exception_t, code, func, description) { + assert_throws(null, func, description); + exception_t.step(function() { + assert_throws(code, func, description); + }); +} + // We do a fresh load of the subframes for each test to minimize side-effects. // It would be nice to reload ourselves as well, but we can't do that without // disrupting the test harness. function runNextTest() { var entry = testList.shift(); - test(entry[0], entry[1]); + var fun = entry[0]; + var desc = entry[1]; + var main_t = async_test(desc); + var exception_t = async_test(desc + ' (exception type)'); + main_t.add_cleanup(function() { + exception_t.unreached_func('Main test failed')(); + }); + main_t.step(function() { + fun(exception_t); + }); + exception_t.done(); + main_t.done(); if (testList.length != 0) reloadSubframes(runNextTest); else
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/dynamic-markup-insertion/document-write/empty.html b/third_party/WebKit/LayoutTests/external/wpt/html/dom/dynamic-markup-insertion/document-write/empty.html new file mode 100644 index 0000000..0dc101b --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/dynamic-markup-insertion/document-write/empty.html
@@ -0,0 +1 @@ +<html><body></body></html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/dynamic-markup-insertion/document-write/write-active-document-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/dom/dynamic-markup-insertion/document-write/write-active-document-expected.txt new file mode 100644 index 0000000..7c64cdb14 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/dynamic-markup-insertion/document-write/write-active-document-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +FAIL document.write only writes to active documents assert_equals: expected (string) "IFRAME" but got (undefined) undefined +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/dynamic-markup-insertion/document-write/write-active-document.html b/third_party/WebKit/LayoutTests/external/wpt/html/dom/dynamic-markup-insertion/document-write/write-active-document.html new file mode 100644 index 0000000..6faffd8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/dynamic-markup-insertion/document-write/write-active-document.html
@@ -0,0 +1,35 @@ +<!doctype html> +<title>document.write only writes to active documents</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body><div id="log"></div></body> +<script> + async_test(function(t) { + var child = document.createElement("iframe"); + child.src = "empty.html?1"; + child.onload = t.step_func(function() { + var child1 = child.contentDocument; + var link = child1.createElement("a"); + link.href = "data:text/html,Clicked."; + link.innerText = "Link."; + child1.body.appendChild(link); + var grandchild = child1.createElement("iframe"); + grandchild.src = "empty.html?2"; + grandchild.onload = t.step_func(function() { + var grandchild1 = grandchild.contentDocument; + child.onload = t.step_func(function() { + // This is a write to an inactive document + child1.write('WRITE HAPPENED'); + assert_equals(child1.body.lastChild.tagName, "IFRAME"); + // This is a write to an active but not fully active document + grandchild1.write('WRITE HAPPENED'); + assert_equals(grandchild1.body.innerHTML, "WRITE HAPPENED"); + t.done(); + }); + link.click(); + }); + child1.body.appendChild(grandchild); + }); + document.body.appendChild(child); + }); +</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-synchronously-discard.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-synchronously-discard.html new file mode 100644 index 0000000..c339525 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-synchronously-discard.html
@@ -0,0 +1,32 @@ +<!doctype html> +<meta charset=utf-8> +<title>IFrame discards are processed synchronously</title> +<body></body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + async_test(function(t) { + var child = document.createElement("iframe"); + child.src = "support/blank.htm?1"; + child.onload = t.step_func(function () { + var childWindow = child.contentWindow; + var grandchild = childWindow.document.createElement("iframe"); + grandchild.src = "blank.htm?2"; + grandchild.onload = t.step_func(function () { + var grandchildWindow = grandchild.contentWindow; + assert_equals(child.contentWindow, childWindow, "child window"); + assert_equals(childWindow.parent, window, "child parentage"); + assert_equals(grandchild.contentWindow, grandchildWindow, "grandchild window"); + assert_equals(grandchildWindow.parent, childWindow, "grandchild parentage"); + document.body.removeChild(child); + assert_equals(child.contentWindow, null, "child should be discarded"); + assert_equals(childWindow.parent, null, "child window should be discarded"); + assert_equals(grandchild.contentWindow, null, "grandchild should be discarded"); + assert_equals(grandchildWindow.parent, null, "grandchild window should be discarded"); + t.done(); + }); + childWindow.document.body.appendChild(grandchild); + }); + document.body.appendChild(child); + }); +</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/not-rendered-dimension-getter.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/not-rendered-dimension-getter.html new file mode 100644 index 0000000..4d929fd --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/not-rendered-dimension-getter.html
@@ -0,0 +1,22 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Image intrinsic dimensions are returned if the image isn't rendered</title> +<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-img-width"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="container" style="display: none"> +</div> +<script> +async_test(function(t) { + var img = document.createElement('img'); + img.onload = t.step_func_done(function() { + assert_equals(img.width, 389, "intrinsic width should've been returned") + assert_equals(img.height, 590, "intrinsic height should've been returned") + document.getElementById('container').appendChild(img); + assert_equals(img.width, 389, "intrinsic width should've been returned"); + assert_equals(img.height, 590, "intrinsic height should've been returned"); + }); + img.src = "image-1.jpg"; +}); +</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/links/linktypes/alternate-import.css b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/links/linktypes/alternate-import.css new file mode 100644 index 0000000..7db3df1d --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/links/linktypes/alternate-import.css
@@ -0,0 +1,3 @@ +body { + background-color: black; +}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/links/linktypes/alternate.css b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/links/linktypes/alternate.css index 05920c61..b101ab91 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/links/linktypes/alternate.css +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/links/linktypes/alternate.css
@@ -1,3 +1,5 @@ +@import url("alternate-import.css"); + div { background-color: red; }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/body-exposed-window-event-handlers-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/body-exposed-window-event-handlers-expected.txt new file mode 100644 index 0000000..6f7d3a8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/body-exposed-window-event-handlers-expected.txt
@@ -0,0 +1,83 @@ +This is a testharness.js-based test. +PASS Return null when getting the load event handler of a windowless body +PASS Ignore setting of load window event handlers on windowless body +PASS Return null when getting the resize event handler of a windowless body +PASS Ignore setting of resize window event handlers on windowless body +PASS Return null when getting the blur event handler of a windowless body +PASS Ignore setting of blur window event handlers on windowless body +PASS Return null when getting the focus event handler of a windowless body +PASS Ignore setting of focus window event handlers on windowless body +PASS Return null when getting the scroll event handler of a windowless body +PASS Ignore setting of scroll window event handlers on windowless body +FAIL Return null when getting the afterprint event handler of a windowless body assert_equals: expected (object) null but got (undefined) undefined +FAIL Ignore setting of afterprint window event handlers on windowless body assert_equals: expected (object) null but got (function) function "function () { return "Handler attached to windowless element"; }" +FAIL Return null when getting the beforeprint event handler of a windowless body assert_equals: expected (object) null but got (undefined) undefined +FAIL Ignore setting of beforeprint window event handlers on windowless body assert_equals: expected (object) null but got (function) function "function () { return "Handler attached to windowless element"; }" +PASS Return null when getting the beforeunload event handler of a windowless body +PASS Ignore setting of beforeunload window event handlers on windowless body +PASS Return null when getting the hashchange event handler of a windowless body +PASS Ignore setting of hashchange window event handlers on windowless body +PASS Return null when getting the languagechange event handler of a windowless body +PASS Ignore setting of languagechange window event handlers on windowless body +PASS Return null when getting the message event handler of a windowless body +PASS Ignore setting of message window event handlers on windowless body +PASS Return null when getting the offline event handler of a windowless body +PASS Ignore setting of offline window event handlers on windowless body +PASS Return null when getting the online event handler of a windowless body +PASS Ignore setting of online window event handlers on windowless body +PASS Return null when getting the pagehide event handler of a windowless body +PASS Ignore setting of pagehide window event handlers on windowless body +PASS Return null when getting the pageshow event handler of a windowless body +PASS Ignore setting of pageshow window event handlers on windowless body +PASS Return null when getting the popstate event handler of a windowless body +PASS Ignore setting of popstate window event handlers on windowless body +PASS Return null when getting the rejectionhandled event handler of a windowless body +PASS Ignore setting of rejectionhandled window event handlers on windowless body +PASS Return null when getting the storage event handler of a windowless body +PASS Ignore setting of storage window event handlers on windowless body +PASS Return null when getting the unhandledrejection event handler of a windowless body +PASS Ignore setting of unhandledrejection window event handlers on windowless body +PASS Return null when getting the unload event handler of a windowless body +PASS Ignore setting of unload window event handlers on windowless body +PASS Return null when getting the load event handler of a windowless frameset +PASS Ignore setting of load window event handlers on windowless frameset +PASS Return null when getting the resize event handler of a windowless frameset +PASS Ignore setting of resize window event handlers on windowless frameset +PASS Return null when getting the blur event handler of a windowless frameset +PASS Ignore setting of blur window event handlers on windowless frameset +PASS Return null when getting the focus event handler of a windowless frameset +PASS Ignore setting of focus window event handlers on windowless frameset +PASS Return null when getting the scroll event handler of a windowless frameset +PASS Ignore setting of scroll window event handlers on windowless frameset +FAIL Return null when getting the afterprint event handler of a windowless frameset assert_equals: expected (object) null but got (undefined) undefined +FAIL Ignore setting of afterprint window event handlers on windowless frameset assert_equals: expected (object) null but got (function) function "function () { return "Handler attached to windowless element"; }" +FAIL Return null when getting the beforeprint event handler of a windowless frameset assert_equals: expected (object) null but got (undefined) undefined +FAIL Ignore setting of beforeprint window event handlers on windowless frameset assert_equals: expected (object) null but got (function) function "function () { return "Handler attached to windowless element"; }" +PASS Return null when getting the beforeunload event handler of a windowless frameset +PASS Ignore setting of beforeunload window event handlers on windowless frameset +PASS Return null when getting the hashchange event handler of a windowless frameset +PASS Ignore setting of hashchange window event handlers on windowless frameset +PASS Return null when getting the languagechange event handler of a windowless frameset +PASS Ignore setting of languagechange window event handlers on windowless frameset +PASS Return null when getting the message event handler of a windowless frameset +PASS Ignore setting of message window event handlers on windowless frameset +PASS Return null when getting the offline event handler of a windowless frameset +PASS Ignore setting of offline window event handlers on windowless frameset +PASS Return null when getting the online event handler of a windowless frameset +PASS Ignore setting of online window event handlers on windowless frameset +PASS Return null when getting the pagehide event handler of a windowless frameset +PASS Ignore setting of pagehide window event handlers on windowless frameset +PASS Return null when getting the pageshow event handler of a windowless frameset +PASS Ignore setting of pageshow window event handlers on windowless frameset +PASS Return null when getting the popstate event handler of a windowless frameset +PASS Ignore setting of popstate window event handlers on windowless frameset +PASS Return null when getting the rejectionhandled event handler of a windowless frameset +PASS Ignore setting of rejectionhandled window event handlers on windowless frameset +PASS Return null when getting the storage event handler of a windowless frameset +PASS Ignore setting of storage window event handlers on windowless frameset +PASS Return null when getting the unhandledrejection event handler of a windowless frameset +PASS Ignore setting of unhandledrejection window event handlers on windowless frameset +PASS Return null when getting the unload event handler of a windowless frameset +PASS Ignore setting of unload window event handlers on windowless frameset +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/body-exposed-window-event-handlers.html b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/body-exposed-window-event-handlers.html new file mode 100644 index 0000000..0bd26dc --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/body-exposed-window-event-handlers.html
@@ -0,0 +1,49 @@ +<!doctype html> +<meta charset="utf-8"> +<title></title> +<body></body> +<script src="https://code.jquery.com/jquery-1.10.2.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +var elements = ['body', 'frameset']; +var handlers = [ + 'load', 'resize', 'blur', 'focus', 'scroll', + 'afterprint', 'beforeprint', 'beforeunload', 'hashchange', + 'languagechange', 'message', 'offline', 'online', 'pagehide', + 'pageshow', 'popstate', 'rejectionhandled', 'storage', + 'unhandledrejection', 'unload']; + +elements.forEach(function (elementName) { + handlers.forEach(function (eventName) { + var handlerName = "on" + eventName; + + test(function() { + var windowHandler = function () { return "Handler attached to the window"; }; + window[handlerName] = windowHandler; + + var d = (new DOMParser).parseFromString('', 'text/html'); + var b = d.createElement(elementName); + + assert_equals(b[handlerName], null); + + window[handlerName] = null; + }, "Return null when getting the " + eventName + " event handler of a windowless " + elementName); + + test(function() { + var windowHandler = function () { return "Handler attached to the window"; }; + window[handlerName] = windowHandler; + + var d = (new DOMParser).parseFromString('', 'text/html'); + var b = d.createElement(elementName); + b[handlerName] = function() { return "Handler attached to windowless element"; }; + + assert_equals(window[handlerName], windowHandler); + assert_equals(b[handlerName], null); + + // Clean up window event handler + window[handlerName] = null; + }, "Ignore setting of " + eventName + " window event handlers on windowless " + elementName); + }); +}); +</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/remote-playback/README.md b/third_party/WebKit/LayoutTests/external/wpt/remote-playback/README.md new file mode 100644 index 0000000..de0a6d8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/remote-playback/README.md
@@ -0,0 +1,19 @@ +# Remote Playback API specification Tests + +The Remote Playback API can be found here: + +GitHub repository: https://github.com/w3c/remote-playback/ + +File an issue: https://github.com/w3c/remote-playback/issues/new + +## Hardware/network dependency + +The Remote Playback API requires to communicate with a device over the network. +Some behavior would require a real devices to be implemented. In order to keep +these tests automated, only behaviors that can be run without user gesture or +specific configurations are available here. + +## TODO + +Some tests are missing, including, but not only: +* IDL tests
diff --git a/third_party/WebKit/LayoutTests/external/wpt/remote-playback/cancel-watch-availability.html b/third_party/WebKit/LayoutTests/external/wpt/remote-playback/cancel-watch-availability.html new file mode 100644 index 0000000..99cae8e --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/remote-playback/cancel-watch-availability.html
@@ -0,0 +1,44 @@ +<!DOCTYPE html> +<html> +<title>Tests various ways to call cancelWatchAvailability()</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/media.js"></script> +<script> +async_test(t => { + var v = document.createElement('video'); + v.src = getVideoURI('movie_5'); + + v.remote.watchAvailability(function() {}) + .then(t.step_func(id => { + v.remote.cancelWatchAvailability(id).then(t.step_func(function() { + v.remote.cancelWatchAvailability(id).then( + t.unreached_func(), t.step_func_done(e => { + assert_equals(e.name, 'NotFoundError'); + }) + ); + }), t.unreached_func()); + }), t.unreached_func()); +}, 'Test that calling cancelWatchAvailability() with an id does remove the callback.'); + +async_test(t => { + var v = document.createElement('video'); + v.src = getVideoURI('media_5'); + + Promise.all([ + v.remote.watchAvailability(function() {}), + v.remote.watchAvailability(function() {}) + ]).then(t.step_func(ids => { + v.remote.cancelWatchAvailability().then(t.step_func(function() { + v.remote.cancelWatchAvailability(ids[0]).then(t.unreached_func(), t.step_func(function(e) { + assert_equals(e.name, 'NotFoundError'); + v.remote.cancelWatchAvailability(ids[1]) + .then(t.unreached_func(), t.step_func_done(function(e) { + assert_equals(e.name, 'NotFoundError'); + })); + })); + }), t.unreached_func()); + }), t.unreached_func()); +}, 'Test that calling cancelWatchAvailability() without an id removes all the callbacks.'); +</script> +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/remote-playback/disable-remote-playback-cancel-watch-availability-throws.html b/third_party/WebKit/LayoutTests/external/wpt/remote-playback/disable-remote-playback-cancel-watch-availability-throws.html new file mode 100644 index 0000000..fdcc734 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/remote-playback/disable-remote-playback-cancel-watch-availability-throws.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> +<title>Test that calling cancelWatchAvailability() when disableRemotePlayback attribute is set throws an exception</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/media.js"></script> +<script> +async_test(t => { + var v = document.createElement('video'); + v.src = getVideoURI('movie_5'); + + v.remote.watchAvailability(function() {}) + .then(id => { + v.disableRemotePlayback = true; + v.remote.cancelWatchAvailability(id).then( + t.unreached_func(), + t.step_func(e => { + assert_equals(e.name, 'InvalidStateError'); + v.remote.cancelWatchAvailability().then( + t.unreached_func(), + t.step_func_done(e => { + assert_equals(e.name, 'InvalidStateError'); + }) + ); + })); + }, t.unreached_func()); +}, 'Test that calling cancelWatchAvailability() when disableRemotePlayback attribute is set throws an exception.'); +</script> +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/remote-playback/disable-remote-playback-prompt-throws.html b/third_party/WebKit/LayoutTests/external/wpt/remote-playback/disable-remote-playback-prompt-throws.html new file mode 100644 index 0000000..7ddc2ad1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/remote-playback/disable-remote-playback-prompt-throws.html
@@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> +<title>Test that calling prompt() when disableRemotePlayback attribute is set throws an exception</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/media.js"></script> +<script> +promise_test(t => { + var v = document.createElement('video'); + v.src = getVideoURI('movie_5'); + v.disableRemotePlayback = true; + + return promise_rejects(t, 'InvalidStateError', v.remote.prompt()); +}, 'Test that calling prompt() when disableRemotePlayback attribute is set throws an exception.'); +</script> +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/remote-playback/disable-remote-playback-watch-availability-throws.html b/third_party/WebKit/LayoutTests/external/wpt/remote-playback/disable-remote-playback-watch-availability-throws.html new file mode 100644 index 0000000..3c21f01 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/remote-playback/disable-remote-playback-watch-availability-throws.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<title>Test that calling watchAvailability() when disableRemotePlayback attribute is set throws an exception</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/media.js"></script> +<script> +promise_test(t => { + var v = document.createElement('video'); + v.src = getVideoURI('movie_5'); + v.disableRemotePlayback = true; + + return promise_rejects(t, 'InvalidStateError', + v.remote.watchAvailability(function() {})); +}, 'Test that calling watchAvailability() when disableRemotePlayback attribute is set throws an exception.'); +</script> +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/remote-playback/watch-availability-initial-callback.html b/third_party/WebKit/LayoutTests/external/wpt/remote-playback/watch-availability-initial-callback.html new file mode 100644 index 0000000..851558b --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/remote-playback/watch-availability-initial-callback.html
@@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> +<title>Test that the callback is called once watchAvailability() resolves.</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/media.js"></script> +<script> +async_test(t => { + var v = document.createElement('video'); + v.src = getVideoURI('movie_5'); + + var promiseResolved = false; + + function callback(available) { + assert_true(promiseResolved); + } + + v.remote.watchAvailability(t.step_func_done(callback)).then( + t.step_func(() => { promiseResolved = true; }), t.unreached_func()); +}, 'Test that the callback is called once watchAvailability() resolves.'); +</script> +</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/register-link-header.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/register-link-header.https.html similarity index 64% rename from third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/register-link-header.html rename to third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/register-link-header.https.html index deacae0a..dd71c9b 100644 --- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/register-link-header.html +++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/register-link-header.https.html
@@ -1,16 +1,23 @@ <!DOCTYPE html> -<!-- FIXME: Move this test out of chromium/ when PHP is no longer needed - to set the Link header (crbug.com/347864). ---> +<title>Service Worker: Registration using Link header</title> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> -<script src="../resources/test-helpers.js"></script> +<script src="resources/test-helpers.sub.js"></script> <body> <script> +function get_newest_worker(registration) { + if (registration.installing) + return registration.installing; + if (registration.waiting) + return registration.waiting; + if (registration.active) + return registration.active; +} + promise_test(function(t) { var scope = normalizeURL('resources/blank.html?fetch'); var header = '<empty-worker.js>; rel=serviceworker; scope="' + scope + '"'; - var resource = 'resources/link-header.php?Link=' + + var resource = 'resources/link-header.py?Link=' + encodeURIComponent(header); return with_iframe(scope) .then(frame => @@ -18,13 +25,16 @@ fetch(resource)])) .then(([registration, response]) => { assert_equals(registration.scope, scope); + assert_equals(get_newest_worker(registration).scriptURL, + normalizeURL('resources/empty-worker.js')); + return registration.unregister(); }); }, 'fetch can trigger service worker installation'); promise_test(function(t) { var scope = normalizeURL('resources/blank.html?iframe'); var header = '<empty-worker.js>; rel=serviceworker; scope="' + scope + '"'; - var resource = 'resources/link-header.php?Link=' + + var resource = 'resources/link-header.py?Link=' + encodeURIComponent(header); return with_iframe(scope) .then(frame => @@ -32,13 +42,16 @@ with_iframe(resource)])) .then(([registration, frame]) => { assert_equals(registration.scope, scope); + assert_equals(get_newest_worker(registration).scriptURL, + normalizeURL('resources/empty-worker.js')); + return registration.unregister(); }); }, 'An iframe can trigger service worker installation'); promise_test(function(t) { var scope = normalizeURL('resources/blank.html?css'); var header = '<empty-worker.js>; rel=serviceworker; scope="' + scope + '"'; - var resource = 'resources/link-header.php?Link=' + + var resource = 'resources/link-header.py?Link=' + encodeURIComponent(header); return with_iframe(scope) .then(frame => { @@ -51,6 +64,9 @@ }) .then(registration => { assert_equals(registration.scope, scope); + assert_equals(get_newest_worker(registration).scriptURL, + normalizeURL('resources/empty-worker.js')); + return registration.unregister(); }); }, 'A stylesheet can trigger service worker installation');
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/link-header.py b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/link-header.py new file mode 100644 index 0000000..1ea37c3 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/link-header.py
@@ -0,0 +1,4 @@ +def main(request, response): + if 'Link' in request.GET: + return [('Link', request.GET['Link'])], "" + return [], ""
diff --git a/third_party/WebKit/LayoutTests/external/wpt/workers/semantics/interface-objects/002.worker.js b/third_party/WebKit/LayoutTests/external/wpt/workers/semantics/interface-objects/002.worker.js index 0f51498..8fc0b6a 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/workers/semantics/interface-objects/002.worker.js +++ b/third_party/WebKit/LayoutTests/external/wpt/workers/semantics/interface-objects/002.worker.js
@@ -16,6 +16,7 @@ "DrawingStyle", "CanvasGradient", "CanvasPattern", + "BeforeUnloadEvent", "PopStateEvent", "HashChangeEvent", "PageTransitionEvent",
diff --git a/third_party/WebKit/LayoutTests/fast/block/positioning/fixed-in-abs-in-rel-top-change.html b/third_party/WebKit/LayoutTests/fast/block/positioning/fixed-in-abs-in-rel-top-change.html new file mode 100644 index 0000000..36b6dfe9 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/block/positioning/fixed-in-abs-in-rel-top-change.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<style> + +body { margin: 0; } +.rel { position: relative; } +.abs { position: absolute; } +.fix { position: fixed; } + +</style> +<div class="rel"> + <div class="abs"> + <div class="fix">fixed</div> + </div> +</div> +<script> + +test(() => { + var abs = document.querySelector(".abs"); + var fix = document.querySelector(".fix"); + + assert_equals(fix.offsetTop, 0); + + abs.style.top = "100px"; + assert_equals(fix.offsetTop, 100); +}, "Abs-pos in rel-pos container updates fixed-pos child when moved."); + +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-image-side-reduction-expected.png b/third_party/WebKit/LayoutTests/fast/borders/border-image-side-reduction-expected.png index d3ef3753..b5d6c621 100644 --- a/third_party/WebKit/LayoutTests/fast/borders/border-image-side-reduction-expected.png +++ b/third_party/WebKit/LayoutTests/fast/borders/border-image-side-reduction-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/access-zero-sized-canvas-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/access-zero-sized-canvas-expected.txt deleted file mode 100644 index 228b9ad4..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/access-zero-sized-canvas-expected.txt +++ /dev/null
@@ -1,2 +0,0 @@ -This test ensures that accessing the context of a zero sized canvas does not crash. -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/access-zero-sized-canvas.html b/third_party/WebKit/LayoutTests/fast/canvas/access-zero-sized-canvas.html index 3796142..9e7a488 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/access-zero-sized-canvas.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/access-zero-sized-canvas.html
@@ -1,10 +1,16 @@ -This test ensures that accessing the context of a zero sized canvas does not crash. -<canvas id="canvas" width="0" height="0"></canvas><br /> +<html> +<head> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +</head> +<canvas id="canvas" width="0" height="0"></canvas> +<body> <script> -if (window.testRunner) - testRunner.dumpAsText(); - -var context = document.getElementById("canvas").getContext("2d"); -context.fillStyle = "green"; - +test(function(t) { + var context = document.getElementById("canvas").getContext("2d"); + context.fillStyle = "green"; +}, 'This test ensures that accessing the context of a zero sized canvas does not crash.'); </script> +</body> +</html> +
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/alpha-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/alpha-expected.txt deleted file mode 100644 index 6ef91db..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/alpha-expected.txt +++ /dev/null
@@ -1,31 +0,0 @@ -Series of tests for canvas alpha - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS ctx1.getContextAttributes().alpha is true -PASS imgData1.data[0] is 0 -PASS imgData1.data[1] is 0 -PASS imgData1.data[2] is 0 -PASS imgData1.data[3] is 0 -PASS ctx2.getContextAttributes().alpha is true -PASS imgData2.data[0] is 0 -PASS imgData2.data[1] is 0 -PASS imgData2.data[2] is 0 -PASS imgData2.data[3] is 0 -PASS ctx3.getContextAttributes().alpha is false -PASS ctx4.getContextAttributes().alpha is true -PASS imgData4.data[0] is 0 -PASS imgData4.data[1] is 0 -PASS imgData4.data[2] is 0 -PASS imgData4.data[3] is 0 -PASS attrs.alpha is true -PASS ctx4.getContextAttributes().alpha is true -PASS imgData4.data[0] is 0 -PASS imgData4.data[1] is 0 -PASS imgData4.data[2] is 0 -PASS imgData4.data[3] is 0 -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/alpha.html b/third_party/WebKit/LayoutTests/fast/canvas/alpha.html index 2877d2e..e448ec2 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/alpha.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/alpha.html
@@ -1,7 +1,8 @@ <!DOCTYPE HTML> <html> <head> -<script src="../../resources/js-test.js"></script> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <style> #canvas3 { @@ -11,12 +12,61 @@ } </style> -</head> -<body> <canvas id="canvas1" width="8" height="8"></canvas> <canvas id="canvas2" width="8" height="8"></canvas> <canvas id="canvas3" width="8" height="8"></canvas> <canvas id="canvas4" width="8" height="8"></canvas> -<script src="alpha.js"></script> +</head> +<body> +<script> +test(function(t) { + var canvas1 = document.getElementById('canvas1'); + var canvas2 = document.getElementById('canvas2'); + var canvas3 = document.getElementById('canvas3'); + var canvas4 = document.getElementById('canvas4'); + + var ctx1 = canvas1.getContext('2d'); + var ctx2 = canvas2.getContext('2d', {} ); + var ctx3 = canvas3.getContext('2d', { alpha: false } ); + var ctx4 = canvas4.getContext('2d', { alpha: true } ); + + assert_equals(ctx1.getContextAttributes().alpha,true); + var imgData1 = ctx1.getImageData(0, 0, 1, 1); + assert_equals(imgData1.data[0],0); + assert_equals(imgData1.data[1],0); + assert_equals(imgData1.data[2],0); + assert_equals(imgData1.data[3],0); + + assert_equals(ctx2.getContextAttributes().alpha,true); + var imgData2 = ctx2.getImageData(0, 0, 1, 1); + assert_equals(imgData2.data[0],0); + assert_equals(imgData2.data[1],0); + assert_equals(imgData2.data[2],0); + assert_equals(imgData2.data[3],0); + + assert_equals(ctx3.getContextAttributes().alpha,false); + assert_equals(ctx4.getContextAttributes().alpha,true); + + var imgData4 = ctx4.getImageData(0, 0, 1, 1); + assert_equals(imgData4.data[0],0); + assert_equals(imgData4.data[1],0); + assert_equals(imgData4.data[2],0); + assert_equals(imgData4.data[3],0); + + // Check that mutating the returned value of getContextAttributes() doesn't + // affect the existing canvas, or the values of subsequent calls to + // getContextAttributes(). + var attrs = ctx4.getContextAttributes(); + assert_equals(attrs.alpha,true); + attrs.alpha = false; + + var imgData4 = ctx4.getImageData(0, 0, 1, 1); + assert_equals(ctx4.getContextAttributes().alpha,true); + assert_equals(imgData4.data[0],0); + assert_equals(imgData4.data[1],0); + assert_equals(imgData4.data[2],0); + assert_equals(imgData4.data[3],0); +}, 'Series of tests for canvas alpha'); +</script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/alpha.js b/third_party/WebKit/LayoutTests/fast/canvas/alpha.js deleted file mode 100644 index c546db77..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/alpha.js +++ /dev/null
@@ -1,50 +0,0 @@ -description("Series of tests for canvas alpha"); - -if (window.testRunner) - testRunner.dumpAsTextWithPixelResults(); - -var canvas1 = document.getElementById("canvas1"); -var canvas2 = document.getElementById("canvas2"); -var canvas3 = document.getElementById("canvas3"); -var canvas4 = document.getElementById("canvas4"); - -var ctx1 = canvas1.getContext("2d"); -var ctx2 = canvas2.getContext("2d", {} ); -var ctx3 = canvas3.getContext("2d", { alpha: false } ); -var ctx4 = canvas4.getContext("2d", { alpha: true } ); - -shouldBe("ctx1.getContextAttributes().alpha", "true"); -var imgData1 = ctx1.getImageData(0, 0, 1, 1); -shouldBe("imgData1.data[0]", "0"); -shouldBe("imgData1.data[1]", "0"); -shouldBe("imgData1.data[2]", "0"); -shouldBe("imgData1.data[3]", "0"); - -shouldBe("ctx2.getContextAttributes().alpha", "true"); -var imgData2 = ctx2.getImageData(0, 0, 1, 1); -shouldBe("imgData2.data[0]", "0"); -shouldBe("imgData2.data[1]", "0"); -shouldBe("imgData2.data[2]", "0"); -shouldBe("imgData2.data[3]", "0"); - -shouldBe("ctx3.getContextAttributes().alpha", "false"); - -shouldBe("ctx4.getContextAttributes().alpha", "true"); -var imgData4 = ctx4.getImageData(0, 0, 1, 1); -shouldBe("imgData4.data[0]", "0"); -shouldBe("imgData4.data[1]", "0"); -shouldBe("imgData4.data[2]", "0"); -shouldBe("imgData4.data[3]", "0"); - -// Check that mutating the returned value of getContextAttributes() doesn't -// affect the existing canvas, or the values of subsequent calls to -// getContextAttributes(). -var attrs = ctx4.getContextAttributes(); -shouldBe("attrs.alpha", "true"); -attrs.alpha = false; -var imgData4 = ctx4.getImageData(0, 0, 1, 1); -shouldBe("ctx4.getContextAttributes().alpha", "true"); -shouldBe("imgData4.data[0]", "0"); -shouldBe("imgData4.data[1]", "0"); -shouldBe("imgData4.data[2]", "0"); -shouldBe("imgData4.data[3]", "0");
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/arc-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/arc-crash-expected.txt deleted file mode 100644 index 2494a1f..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/arc-crash-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ - -This tests that we don't crash when passing inf as a parameter to arc -Test passed. -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/arc-crash.html b/third_party/WebKit/LayoutTests/fast/canvas/arc-crash.html index d5ac97d..6569403 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/arc-crash.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/arc-crash.html
@@ -1,15 +1,10 @@ -<html> -<head> -<script type="text/javascript"> -function debug(str) { - var c = document.getElementById('console') - c.appendChild(document.createTextNode(str + '\n')); -} - -function runTests() { - debug("This tests that we don't crash when passing inf as a parameter to arc"); - var canvas = document.getElementById("test"); - var context = canvas.getContext("2d"); +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<canvas id="test" width="100" height="100"></canvas><br /> +<script> +test(function(t) { + var canvas = document.getElementById('test'); + var context = canvas.getContext('2d'); context.fillStyle = '#f00'; context.fillRect(0, 0, canvas.width, canvas.height); try { @@ -28,18 +23,5 @@ } context.fillStyle = '#0f0'; context.fillRect(0, 0, canvas.width, canvas.height); - debug("Test passed."); - if (window.testRunner) - testRunner.dumpAsText(); -} +}, "This tests that we don't crash when passing inf as a parameter to arc"); </script> -<title>borkedness</title> -</head> -<body> - <canvas id="test" width="100" height="100"></canvas><br /> - <pre id="console"></pre> - <script> - runTests(); - </script> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/arc360-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/arc360-expected.txt deleted file mode 100644 index f3aa9264..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/arc360-expected.txt +++ /dev/null
@@ -1 +0,0 @@ -Test canvas arc() start / end points when the arc is >= 360 degrees. The result should be a circle with two line segments connected to the left hand side, towards the top left and bottom left corners.
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/arc360.html b/third_party/WebKit/LayoutTests/fast/canvas/arc360.html index 139bc779..1d4704a 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/arc360.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/arc360.html
@@ -1,18 +1,16 @@ -<body> -<p>Test canvas arc() start / end points when the arc is >= 360 degrees. The result should be a circle with two line segments connected to the left hand side, towards the top left and bottom left corners. +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <canvas id="mycanvas" width="400" height="400"></canvas> <script> -if (window.testRunner) - testRunner.dumpAsTextWithPixelResults(); - -var canvas = document.getElementById('mycanvas'); -var ctx = canvas.getContext('2d'); -var cx = 200, cy = 200, radius = 100; -ctx.lineWidth = 10; -ctx.beginPath(); -ctx.moveTo(0, 100); -ctx.arc(cx, cy, radius, -Math.PI, Math.PI, false); -ctx.lineTo(0, 300); -ctx.stroke(); +test(function(t) { + var canvas = document.getElementById('mycanvas'); + var ctx = canvas.getContext('2d'); + var cx = 200, cy = 200, radius = 100; + ctx.lineWidth = 10; + ctx.beginPath(); + ctx.moveTo(0, 100); + ctx.arc(cx, cy, radius, -Math.PI, Math.PI, false); + ctx.lineTo(0, 300); + ctx.stroke(); +}, 'Test canvas arc() start / end points when the arc is >= 360 degrees. The result should be a circle with two line segments connected to the left hand side, towards the top left and bottom left corners.'); </script> -</body>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/bug503422-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/bug503422-expected.txt deleted file mode 100644 index 2e98820d..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/bug503422-expected.txt +++ /dev/null
@@ -1,3 +0,0 @@ -Regression test for crbug.com/503422. Test passes by not crashing. - -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/bug503422.html b/third_party/WebKit/LayoutTests/fast/canvas/bug503422.html index 67209cf..60dbdb71 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/bug503422.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/bug503422.html
@@ -1,10 +1,10 @@ -<p>Regression test for crbug.com/503422. Test passes by not crashing.</p> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <canvas id=mycanvas width=400 height=400</script> <script> -if (window.testRunner) { - testRunner.dumpAsText(); -} -var canvas = document.getElementById('mycanvas'); -var ctx = canvas.getContext('2d'); -ctx.ellipse(80, 0, 10, 4294967277, Math.PI / -84, -Math.PI / 2147483436, false); +test(function(t) { + var canvas = document.getElementById('mycanvas'); + var ctx = canvas.getContext('2d'); + ctx.ellipse(80, 0, 10, 4294967277, Math.PI / -84, -Math.PI / 2147483436, false); +}, 'Regression test for crbug.com/503422. Test passes by not crashing.'); </script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/bug544329-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/bug544329-expected.txt deleted file mode 100644 index 19bcd97..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/bug544329-expected.txt +++ /dev/null
@@ -1,3 +0,0 @@ -Regression test for crbug.com/544329. Test passes by not crashing. - -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/bug544329.html b/third_party/WebKit/LayoutTests/fast/canvas/bug544329.html index 9da67d0..c6a536c 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/bug544329.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/bug544329.html
@@ -1,10 +1,10 @@ -<p>Regression test for crbug.com/544329. Test passes by not crashing.</p> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <canvas id='c' style="padding-right: 4294967292; border-right: 124px solid black;"></canvas> <script> -if (window.testRunner) { - testRunner.dumpAsText(); -} -var canvas = document.getElementById('c'); -var ctx = canvas.getContext('2d'); -ctx.getImageData(0, 0, 1, 1); +test(function(t) { + var canvas = document.getElementById('c'); + var ctx = canvas.getContext('2d'); + ctx.getImageData(0, 0, 1, 1); +}, 'Regression test for crbug.com/544329. Test passes by not crashing.'); </script> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-2d-imageData-create-nonfinite-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-2d-imageData-create-nonfinite-expected.txt deleted file mode 100644 index b1f07ec..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-2d-imageData-create-nonfinite-expected.txt +++ /dev/null
@@ -1,16 +0,0 @@ -Test the argument bounds of canvas createImageData. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS ctx.createImageData(Infinity, Infinity) threw exception TypeError: Failed to execute 'createImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.createImageData(Infinity, 10) threw exception TypeError: Failed to execute 'createImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.createImageData(-Infinity, 10) threw exception TypeError: Failed to execute 'createImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.createImageData(10, Infinity) threw exception TypeError: Failed to execute 'createImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.createImageData(10, -Infinity) threw exception TypeError: Failed to execute 'createImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.createImageData(NaN, 10) threw exception TypeError: Failed to execute 'createImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.createImageData(10, NaN) threw exception TypeError: Failed to execute 'createImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-2d-imageData-create-nonfinite.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-2d-imageData-create-nonfinite.html index 382708f..4835c1a8 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-2d-imageData-create-nonfinite.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-2d-imageData-create-nonfinite.html
@@ -1,9 +1,17 @@ -<!DOCTYPE HTML> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> -<body> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <canvas id="canvas" width=600 height=300> -<script src="resources/canvas-2d-imageData-create-nonfinite.js"></script> -</body> +<script> +test(function(t) { + var canvas = document.getElementById('canvas'); + var ctx = canvas.getContext('2d'); + + assert_throws(null, function() {ctx.createImageData(Infinity, Infinity);}, "Failed to execute 'createImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.."); + assert_throws(null, function() {ctx.createImageData(Infinity, 10);}, "Failed to execute 'createImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.."); + assert_throws(null, function() {ctx.createImageData(-Infinity, 10);}, "Failed to execute 'createImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.."); + assert_throws(null, function() {ctx.createImageData(10, Infinity);}, "Failed to execute 'createImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.."); + assert_throws(null, function() {ctx.createImageData(10, -Infinity);}, "Failed to execute 'createImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.."); + assert_throws(null, function() {ctx.createImageData(NaN, 10);}, "Failed to execute 'createImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.."); + assert_throws(null, function() {ctx.createImageData(10, NaN);}, "Failed to execute 'createImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.."); +}, 'Test the argument bounds of canvas createImageData.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-after-destroy-iframe-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-after-destroy-iframe-expected.txt deleted file mode 100644 index a8809630..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-after-destroy-iframe-expected.txt +++ /dev/null
@@ -1,18 +0,0 @@ -PASS successfullyParsed is true - -TEST COMPLETE -check if re-parenting canvas keeps its context. -PASS data[0] is 255 -PASS data[1] is 0 -PASS data[2] is 0 -PASS data[0] is 255 -PASS data[1] is 0 -PASS data[2] is 0 -check if detaching canvas loses its context. -PASS data[0] is 255 -PASS data[1] is 0 -PASS data[2] is 0 -PASS data[0] is 0 -PASS data[1] is 0 -PASS data[2] is 0 -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-after-destroy-iframe.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-after-destroy-iframe.html index 1928f4b2..36553bb 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-after-destroy-iframe.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-after-destroy-iframe.html
@@ -1,15 +1,11 @@ <!DOCTYPE html> <html> <head> - <script src="../../resources/js-test.js"></script> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> </head> <body> <script> -if (window.testRunner) { - testRunner.dumpAsText(); - testRunner.waitUntilDone(); -} - var barrier = 2; function frameLoaded() { @@ -20,13 +16,13 @@ function runTest() { - debug("check if re-parenting canvas keeps its context.") - canvasTest(document.getElementById("frame1"), true); - debug("check if detaching canvas loses its context.") - canvasTest(document.getElementById("frame2"), false); + test(function(t) { + canvasTest(document.getElementById("frame1"), true); + }, 'check if re-parenting canvas keeps its context.'); - if (window.testRunner) - testRunner.notifyDone(); + test(function(t) { + canvasTest(document.getElementById("frame2"), false); + }, 'check if detaching canvas loses its context.'); } var data; @@ -39,9 +35,9 @@ var imageData; imageData = ctx.getImageData(100, 100, 1, 1); data = imageData.data; - shouldBe('data[0]', '255'); - shouldBe('data[1]', '0'); - shouldBe('data[2]', '0'); + assert_equals(data[0], 255); + assert_equals(data[1], 0); + assert_equals(data[2], 0); if (adoptCanvas) parent.appendChild(canvas); @@ -50,13 +46,13 @@ imageData = ctx.getImageData(100, 100, 1, 1); data = imageData.data; if (adoptCanvas) { - shouldBe('data[0]', '255'); + assert_equals(data[0], 255); } else { // GC causes active DOM stop and canvas loses its context. - shouldBe('data[0]', '0'); + assert_equals(data[0], 0); } - shouldBe('data[1]', '0'); - shouldBe('data[2]', '0'); + assert_equals(data[1], 0); + assert_equals(data[2], 0); } </script> <div id="parent">
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-after-detachment-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-after-detachment-expected.txt deleted file mode 100644 index b1db674..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-after-detachment-expected.txt +++ /dev/null
@@ -1,10 +0,0 @@ -PASS data[0] is 255 -PASS data[1] is 0 -PASS data[2] is 0 -PASS data[0] is 255 -PASS data[1] is 0 -PASS data[2] is 0 -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-after-detachment.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-after-detachment.html index e304ca2..d428f4a1 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-after-detachment.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-after-detachment.html
@@ -1,20 +1,9 @@ -<!DOCTYPE html> -<html> -<head> - <script src="../../resources/js-test.js"></script> -</head> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <div id="parent"> <canvas id="mycanvas" width="200" height="200"></canvas> -</div> <script> -if (window.testRunner) { - testRunner.dumpAsText(); - testRunner.waitUntilDone(); -} - -var data; -function runTest() -{ +test(function(t) { var parent = document.getElementById("parent"); var canvas = document.getElementById('mycanvas'); var ctx = canvas.getContext('2d'); @@ -23,10 +12,10 @@ var imageData; imageData = ctx.getImageData(100, 100, 1, 1); - data = imageData.data; - shouldBe('data[0]', '255'); - shouldBe('data[1]', '0'); - shouldBe('data[2]', '0'); + var data = imageData.data; + assert_equals(data[0], 255); + assert_equals(data[1], 0); + assert_equals(data[2], 0); parent.removeChild(canvas); // GC makes sure canvas element is removed. @@ -35,16 +24,8 @@ imageData = ctx.getImageData(100, 100, 1, 1); data = imageData.data; - // The context is valid although the canvas is detached from document. - shouldBe('data[0]', '255'); - shouldBe('data[1]', '0'); - shouldBe('data[2]', '0'); - - if (window.testRunner) - testRunner.notifyDone(); -} - -runTest(); + assert_equals(data[0], 255); + assert_equals(data[1], 0); + assert_equals(data[2], 0); +}, 'Test that the context is valid although the canvas is detached from document.'); </script> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-alphaImageData-behavior-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-alphaImageData-behavior-expected.txt deleted file mode 100644 index 5574fc0..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-alphaImageData-behavior-expected.txt +++ /dev/null
@@ -1,17 +0,0 @@ -Series of tests to ensure correct behaviour of getImageData and putImageData when alpha is involved - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS imgdata[4] is 0 -PASS imgdata[5] is 255 -PASS imgdata[6] is 0 -PASS imgdata[7] is 254 -PASS imgdata[4] is 0 -PASS imgdata[5] is 255 -PASS imgdata[6] is 0 -PASS imgdata[7] is 254 -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-alphaImageData-behavior.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-alphaImageData-behavior.html index d0d17b23a..0813297f 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-alphaImageData-behavior.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-alphaImageData-behavior.html
@@ -1,10 +1,27 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> -<body> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <canvas id="canvas" width="200" height="200"></canvas> -<script src="canvas-alphaImageData-behavior.js"></script> -</body> -</html> + +<script> +test(function(t) { + var ctx = document.getElementById('canvas').getContext('2d'); + ctx.fillStyle = 'rgba(255, 0, 0, 0.01)'; + ctx.fillRect(0, 0, 1, 200); + ctx.fillStyle = 'rgba(0, 255, 0, 0.995)'; + ctx.fillRect(1, 0, 199, 200); + + var imageData = ctx.getImageData(0, 0, 200, 200); + var imgdata = imageData.data; + assert_equals(imgdata[4], 0); + assert_equals(imgdata[5], 255); + assert_equals(imgdata[6], 0); + assert_equals(imgdata[7], 254); + + ctx.putImageData(imageData, 0, 0); + imgdata = ctx.getImageData(0, 0, 200, 200).data; + assert_equals(imgdata[4], 0); + assert_equals(imgdata[5], 255); + assert_equals(imgdata[6], 0); + assert_equals(imgdata[7], 254); +}, 'Series of tests to ensure correct behaviour of getImageData and putImageData when alpha is involved.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-alphaImageData-behavior.js b/third_party/WebKit/LayoutTests/fast/canvas/canvas-alphaImageData-behavior.js deleted file mode 100644 index 77b521f..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-alphaImageData-behavior.js +++ /dev/null
@@ -1,21 +0,0 @@ -description("Series of tests to ensure correct behaviour of getImageData and putImageData when alpha is involved"); -var ctx = document.getElementById('canvas').getContext('2d'); -ctx.fillStyle = 'rgba(255, 0, 0, 0.01)'; -ctx.fillRect(0, 0, 1, 200); -ctx.fillStyle = 'rgba(0, 255, 0, 0.995)'; -ctx.fillRect(1, 0, 199, 200); -var imageData = ctx.getImageData(0, 0, 200, 200); -var imgdata = imageData.data; -shouldBe("imgdata[4]", "0"); -shouldBe("imgdata[5]", "255"); -shouldBe("imgdata[6]", "0"); -shouldBe("imgdata[7]", "254"); - -ctx.putImageData(imageData, 0, 0); - -imgdata = ctx.getImageData(0, 0, 200, 200).data; - -shouldBe("imgdata[4]", "0"); -shouldBe("imgdata[5]", "255"); -shouldBe("imgdata[6]", "0"); -shouldBe("imgdata[7]", "254");
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-color-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-color-expected.txt deleted file mode 100644 index f7d4565..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-color-expected.txt +++ /dev/null
@@ -1,105 +0,0 @@ -Series of tests to ensure correct results on applying different blend modes when drawing a rectangle on top of another. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -Testing blend mode source-over -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode multiply -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 65.25882352941176 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode screen -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 192.74117647058821 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode overlay -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 130.48235294117646 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode darken -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode lighten -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color-dodge -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 255 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color-burn -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 5.930232558139517 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode hard-light -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 130.48235294117646 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode soft-light -PASS actualColor(0, 0)[0] is within 5 of 181.3697880023021 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129.61611515296823 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode difference -PASS actualColor(0, 0)[0] is within 5 of 126 -PASS actualColor(0, 0)[1] is within 5 of 126 -PASS actualColor(0, 0)[2] is within 5 of 0 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode exclusion -PASS actualColor(0, 0)[0] is within 5 of 126 -PASS actualColor(0, 0)[1] is within 5 of 126 -PASS actualColor(0, 0)[2] is within 5 of 127.48235294117649 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode hue -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 181 -PASS actualColor(0, 0)[2] is within 5 of 181 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode saturation -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 181 -PASS actualColor(0, 0)[2] is within 5 of 181 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode luminosity -PASS actualColor(0, 0)[0] is within 5 of 92 -PASS actualColor(0, 0)[1] is within 5 of 218 -PASS actualColor(0, 0)[2] is within 5 of 92 -PASS actualColor(0, 0)[3] is within 5 of 255 - -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-color.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-color.html index d6fc2f8..4db3897 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-color.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-color.html
@@ -1,48 +1,21 @@ -<!DOCTYPE HTML> -<html> -<body> - <script src="../../resources/js-test.js"></script> - <script type="text/javascript" src="canvas-blending-helpers.js"></script> - <script type="text/javascript"> - - description("Series of tests to ensure correct results on applying different blend modes when drawing a rectangle on top of another."); - - var context; - function actualColor(x, y) { - return context.getImageData(x, y, 1, 1).data; - } - - function checkBlendModeResult(i, context, sigma) { - var expectedColor = blendColors([129 / 255, 1, 129 / 255, 1], [1, 129 / 255, 129 / 255, 1], i); - var ac = "actualColor(0, 0)"; - shouldBeCloseTo(ac + "[0]", expectedColor[0], sigma); - shouldBeCloseTo(ac + "[1]", expectedColor[1], sigma); - shouldBeCloseTo(ac + "[2]", expectedColor[2], sigma); - shouldBeCloseTo(ac + "[3]", expectedColor[3], sigma); - } - - function runTest() { - var canvas = document.createElement("canvas"); - var sigma = 5; - canvas.width = 10; - canvas.height = 10; - context = canvas.getContext("2d"); - - for (var i = 0; i < blendModes.length; ++i) { - debug("Testing blend mode " + blendModes[i]); - - context.clearRect(0, 0, 10, 10); - context.save(); - drawBackdropColorInContext(context); - context.globalCompositeOperation = blendModes[i]; - drawSourceColorInContext(context); - checkBlendModeResult(i, context, sigma); - context.restore(); - debug(''); - } - } - - runTest(); - </script> -</body> -</html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script type="text/javascript" src="canvas-blending-helpers.js"></script> +<script> +test(function(t) { + var canvas = document.createElement("canvas"); + var sigma = 5; + canvas.width = 10; + canvas.height = 10; + context = canvas.getContext("2d"); + for (var i = 0; i < blendModes.length; ++i) { + context.clearRect(0, 0, 10, 10); + context.save(); + drawBackdropColorInContext(context); + context.globalCompositeOperation = blendModes[i]; + drawSourceColorInContext(context); + checkBlendModeResult(i, context, sigma); + context.restore(); + } +}, 'Series of tests to ensure correct results on applying different blend modes when drawing a rectangle on top of another.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-gradient-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-gradient-expected.txt deleted file mode 100644 index 423b18e..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-gradient-expected.txt +++ /dev/null
@@ -1,105 +0,0 @@ -Series of tests to ensure correct results on applying different blend modes when drawing a rectangle on top of a gradient. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -Testing blend mode source-over -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode multiply -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 65.25882352941176 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode screen -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 192.74117647058821 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode overlay -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 130.48235294117646 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode darken -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode lighten -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color-dodge -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 255 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color-burn -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 5.930232558139517 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode hard-light -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 130.48235294117646 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode soft-light -PASS actualColor(0, 0)[0] is within 5 of 181.3697880023021 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129.61611515296823 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode difference -PASS actualColor(0, 0)[0] is within 5 of 126 -PASS actualColor(0, 0)[1] is within 5 of 126 -PASS actualColor(0, 0)[2] is within 5 of 0 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode exclusion -PASS actualColor(0, 0)[0] is within 5 of 126 -PASS actualColor(0, 0)[1] is within 5 of 126 -PASS actualColor(0, 0)[2] is within 5 of 127.48235294117649 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode hue -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 181 -PASS actualColor(0, 0)[2] is within 5 of 181 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode saturation -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 181 -PASS actualColor(0, 0)[2] is within 5 of 181 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode luminosity -PASS actualColor(0, 0)[0] is within 5 of 92 -PASS actualColor(0, 0)[1] is within 5 of 218 -PASS actualColor(0, 0)[2] is within 5 of 92 -PASS actualColor(0, 0)[3] is within 5 of 255 - -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-gradient.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-gradient.html index 64fb1c4..40513f7 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-gradient.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-gradient.html
@@ -1,48 +1,21 @@ -<!DOCTYPE HTML> -<html> -<body> - <script src="../../resources/js-test.js"></script> - <script type="text/javascript" src="canvas-blending-helpers.js"></script> - <script type="text/javascript"> - - description("Series of tests to ensure correct results on applying different blend modes when drawing a rectangle on top of a gradient."); - - var context; - function actualColor(x, y) { - return context.getImageData(x, y, 1, 1).data; - } - - function checkBlendModeResult(i, context, sigma) { - var expectedColor = blendColors([129 / 255, 1, 129 / 255, 1], [1, 129 / 255, 129 / 255, 1], i); - var ac = "actualColor(0, 0)"; - shouldBeCloseTo(ac + "[0]", expectedColor[0], sigma); - shouldBeCloseTo(ac + "[1]", expectedColor[1], sigma); - shouldBeCloseTo(ac + "[2]", expectedColor[2], sigma); - shouldBeCloseTo(ac + "[3]", expectedColor[3], sigma); - } - - function runTest() { - var canvas = document.createElement("canvas"); - var sigma = 5; - canvas.width = 10; - canvas.height = 10; - context = canvas.getContext("2d"); - - for (var i = 0; i < blendModes.length; ++i) { - debug("Testing blend mode " + blendModes[i]); - - context.clearRect(0, 0, 10, 10); - context.save(); - drawBackdropColorGradientInContext(context); - context.globalCompositeOperation = blendModes[i]; - drawSourceColorInContext(context); - checkBlendModeResult(i, context, sigma); - context.restore(); - debug(''); - } - } - - runTest(); - </script> -</body> -</html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script type="text/javascript" src="canvas-blending-helpers.js"></script> +<script> +test(function(t) { + var canvas = document.createElement("canvas"); + var sigma = 5; + canvas.width = 10; + canvas.height = 10; + context = canvas.getContext("2d"); + for (var i = 0; i < blendModes.length; ++i) { + context.clearRect(0, 0, 10, 10); + context.save(); + drawBackdropColorGradientInContext(context); + context.globalCompositeOperation = blendModes[i]; + drawSourceColorInContext(context); + checkBlendModeResult(i, context, sigma); + context.restore(); + } +}, 'Series of tests to ensure correct results on applying different blend modes when drawing a rectangle on top of a gradient.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-image-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-image-expected.txt deleted file mode 100644 index f05c1d6..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-image-expected.txt +++ /dev/null
@@ -1,105 +0,0 @@ -Series of tests to ensure correct results on applying different blend modes when drawing a rectangle on top of an image. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -Testing blend mode source-over -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode multiply -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 65.25882352941176 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode screen -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 192.74117647058821 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode overlay -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 130.48235294117646 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode darken -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode lighten -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color-dodge -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 255 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color-burn -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 5.930232558139517 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode hard-light -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 130.48235294117646 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode soft-light -PASS actualColor(0, 0)[0] is within 5 of 181.3697880023021 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129.61611515296823 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode difference -PASS actualColor(0, 0)[0] is within 5 of 126 -PASS actualColor(0, 0)[1] is within 5 of 126 -PASS actualColor(0, 0)[2] is within 5 of 0 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode exclusion -PASS actualColor(0, 0)[0] is within 5 of 126 -PASS actualColor(0, 0)[1] is within 5 of 126 -PASS actualColor(0, 0)[2] is within 5 of 127.48235294117649 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode hue -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 181 -PASS actualColor(0, 0)[2] is within 5 of 181 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode saturation -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 181 -PASS actualColor(0, 0)[2] is within 5 of 181 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode luminosity -PASS actualColor(0, 0)[0] is within 5 of 92 -PASS actualColor(0, 0)[1] is within 5 of 218 -PASS actualColor(0, 0)[2] is within 5 of 92 -PASS actualColor(0, 0)[3] is within 5 of 255 - -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-image.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-image.html index 54d5fbf2..e360339 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-image.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-image.html
@@ -1,63 +1,28 @@ -<!DOCTYPE HTML> -<html> -<head> - <script type="text/javascript"> - if (window.testRunner) - testRunner.waitUntilDone(); - window.jsTestIsAsync = true - </script> -</head> -<body> - <script src="../../resources/js-test.js"></script> - <script type="text/javascript" src="canvas-blending-helpers.js"></script> - <script type="text/javascript"> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script type="text/javascript" src="canvas-blending-helpers.js"></script> +<script> +function drawElement(context, i) { + if (i >= blendModes.length) + return; + context.clearRect(0, 0, 10, 10); + context.save(); + drawBackdropColorImageInContext(context, + function() { + context.globalCompositeOperation = blendModes[i]; + drawSourceColorInContext(context); + checkBlendModeResult(i, context, 5); + context.restore(); + drawElement(context, ++i); + }); +} - description("Series of tests to ensure correct results on applying different blend modes when drawing a rectangle on top of an image."); - - var context; - function actualColor(x, y) { - return context.getImageData(x, y, 1, 1).data; - } - - function checkBlendModeResult(i, context, sigma) { - var expectedColor = blendColors([129 / 255, 1, 129 / 255, 1], [1, 129 / 255, 129 / 255, 1], i); - var ac = "actualColor(0, 0)"; - shouldBeCloseTo(ac + "[0]", expectedColor[0], sigma); - shouldBeCloseTo(ac + "[1]", expectedColor[1], sigma); - shouldBeCloseTo(ac + "[2]", expectedColor[2], sigma); - shouldBeCloseTo(ac + "[3]", expectedColor[3], sigma); - } - - function drawElement(context, i) { - if (i >= blendModes.length) { - finishJSTest(); - return; - } - debug("Testing blend mode " + blendModes[i]); - - context.clearRect(0, 0, 10, 10); - context.save(); - drawBackdropColorImageInContext(context, - function() { - context.globalCompositeOperation = blendModes[i]; - drawSourceColorInContext(context); - checkBlendModeResult(i, context, 5); - context.restore(); - debug(''); - drawElement(context, ++i); - }); - } - - function runTest() { - var canvas = document.createElement("canvas"); - var sigma = 5; - canvas.width = 10; - canvas.height = 10; - context = canvas.getContext("2d"); - drawElement(context, 0); - } - - runTest(); - </script> -</body> -</html> +test(function(t) { + var canvas = document.createElement("canvas"); + var sigma = 5; + canvas.width = 10; + canvas.height = 10; + context = canvas.getContext("2d"); + drawElement(context, 0); +}, 'Series of tests to ensure correct results on applying different blend modes when drawing a rectangle on top of an image.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-pattern-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-pattern-expected.txt deleted file mode 100644 index a7a34d1..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-pattern-expected.txt +++ /dev/null
@@ -1,105 +0,0 @@ -Series of tests to ensure correct results on applying different blend modes when drawing a rectangle on top of an pattern. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -Testing blend mode source-over -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode multiply -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 65.25882352941176 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode screen -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 192.74117647058821 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode overlay -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 130.48235294117646 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode darken -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode lighten -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color-dodge -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 255 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color-burn -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 5.930232558139517 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode hard-light -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 130.48235294117646 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode soft-light -PASS actualColor(0, 0)[0] is within 5 of 181.3697880023021 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129.61611515296823 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode difference -PASS actualColor(0, 0)[0] is within 5 of 126 -PASS actualColor(0, 0)[1] is within 5 of 126 -PASS actualColor(0, 0)[2] is within 5 of 0 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode exclusion -PASS actualColor(0, 0)[0] is within 5 of 126 -PASS actualColor(0, 0)[1] is within 5 of 126 -PASS actualColor(0, 0)[2] is within 5 of 127.48235294117649 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode hue -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 181 -PASS actualColor(0, 0)[2] is within 5 of 181 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode saturation -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 181 -PASS actualColor(0, 0)[2] is within 5 of 181 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode luminosity -PASS actualColor(0, 0)[0] is within 5 of 92 -PASS actualColor(0, 0)[1] is within 5 of 218 -PASS actualColor(0, 0)[2] is within 5 of 92 -PASS actualColor(0, 0)[3] is within 5 of 255 - -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-pattern.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-pattern.html index 1ae5946d..a6aaf2a 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-pattern.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-color-over-pattern.html
@@ -1,63 +1,28 @@ -<!DOCTYPE HTML> -<html> -<head> - <script type="text/javascript"> - if (window.testRunner) - testRunner.waitUntilDone(); - window.jsTestIsAsync = true - </script> -</head> -<body> - <script src="../../resources/js-test.js"></script> - <script type="text/javascript" src="canvas-blending-helpers.js"></script> - <script type="text/javascript"> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script type="text/javascript" src="canvas-blending-helpers.js"></script> +<script> +function drawElement(context, i) { + if (i >= blendModes.length) + return; + context.clearRect(0, 0, 10, 10); + context.save(); + drawBackdropColorPatternInContext(context, + function() { + context.globalCompositeOperation = blendModes[i]; + drawSourceColorInContext(context); + checkBlendModeResult(i, context, 5); + context.restore(); + drawElement(context, ++i); + }); +} - description("Series of tests to ensure correct results on applying different blend modes when drawing a rectangle on top of an pattern."); - - var context; - function actualColor(x, y) { - return context.getImageData(x, y, 1, 1).data; - } - - function checkBlendModeResult(i, context, sigma) { - var expectedColor = blendColors([129 / 255, 1, 129 / 255, 1], [1, 129 / 255, 129 / 255, 1], i); - var ac = "actualColor(0, 0)"; - shouldBeCloseTo(ac + "[0]", expectedColor[0], sigma); - shouldBeCloseTo(ac + "[1]", expectedColor[1], sigma); - shouldBeCloseTo(ac + "[2]", expectedColor[2], sigma); - shouldBeCloseTo(ac + "[3]", expectedColor[3], sigma); - } - - function drawElement(context, i) { - if (i >= blendModes.length) { - finishJSTest(); - return; - } - debug("Testing blend mode " + blendModes[i]); - - context.clearRect(0, 0, 10, 10); - context.save(); - drawBackdropColorPatternInContext(context, - function() { - context.globalCompositeOperation = blendModes[i]; - drawSourceColorInContext(context); - checkBlendModeResult(i, context, 5); - context.restore(); - debug(''); - drawElement(context, ++i); - }); - } - - function runTest() { - var canvas = document.createElement("canvas"); - var sigma = 5; - canvas.width = 10; - canvas.height = 10; - context = canvas.getContext("2d"); - drawElement(context, 0); - } - - runTest(); - </script> -</body> -</html> +test(function(t) { + var canvas = document.createElement("canvas"); + var sigma = 5; + canvas.width = 10; + canvas.height = 10; + context = canvas.getContext("2d"); + drawElement(context, 0); +}, 'Series of tests to ensure correct results on applying different blend modes when drawing a rectangle on top of an pattern.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-fill-style-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-fill-style-expected.txt deleted file mode 100644 index acaa5b7..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-fill-style-expected.txt +++ /dev/null
@@ -1,105 +0,0 @@ -Series of tests to ensure correct results on applying different blend modes when drawing paths. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -Testing blend mode source-over -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode multiply -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 65.25882352941176 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode screen -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 192.74117647058821 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode overlay -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 130.48235294117646 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode darken -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode lighten -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color-dodge -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 255 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color-burn -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 5.930232558139517 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode hard-light -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 130.48235294117646 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode soft-light -PASS actualColor(0, 0)[0] is within 5 of 181.3697880023021 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129.61611515296823 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode difference -PASS actualColor(0, 0)[0] is within 5 of 126 -PASS actualColor(0, 0)[1] is within 5 of 126 -PASS actualColor(0, 0)[2] is within 5 of 0 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode exclusion -PASS actualColor(0, 0)[0] is within 5 of 126 -PASS actualColor(0, 0)[1] is within 5 of 126 -PASS actualColor(0, 0)[2] is within 5 of 127.48235294117649 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode hue -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 181 -PASS actualColor(0, 0)[2] is within 5 of 181 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode saturation -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 181 -PASS actualColor(0, 0)[2] is within 5 of 181 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode luminosity -PASS actualColor(0, 0)[0] is within 5 of 92 -PASS actualColor(0, 0)[1] is within 5 of 218 -PASS actualColor(0, 0)[2] is within 5 of 92 -PASS actualColor(0, 0)[3] is within 5 of 255 - -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-fill-style.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-fill-style.html index abf5e57..9fe1cbe 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-fill-style.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-fill-style.html
@@ -1,48 +1,21 @@ -<!DOCTYPE HTML> -<html> -<body> - <script src="../../resources/js-test.js"></script> - <script type="text/javascript" src="canvas-blending-helpers.js"></script> - <script type="text/javascript"> - - description("Series of tests to ensure correct results on applying different blend modes when drawing paths."); - - var context; - function actualColor(x, y) { - return context.getImageData(x, y, 1, 1).data; - } - - function checkBlendModeResult(i, context, sigma) { - var expectedColor = blendColors([129 / 255, 1, 129 / 255, 1], [1, 129 / 255, 129 / 255, 1], i); - var ac = "actualColor(0, 0)"; - shouldBeCloseTo(ac + "[0]", expectedColor[0], sigma); - shouldBeCloseTo(ac + "[1]", expectedColor[1], sigma); - shouldBeCloseTo(ac + "[2]", expectedColor[2], sigma); - shouldBeCloseTo(ac + "[3]", expectedColor[3], sigma); - } - - function runTest() { - var canvas = document.createElement("canvas"); - var sigma = 5; - canvas.width = 10; - canvas.height = 10; - context = canvas.getContext("2d"); - - for (var i = 0; i < blendModes.length; ++i) { - debug("Testing blend mode " + blendModes[i]); - - context.clearRect(0, 0, 10, 10); - context.save(); - fillPathWithBackdropInContext(context); - context.globalCompositeOperation = blendModes[i]; - fillPathWithSourceInContext(context); - checkBlendModeResult(i, context, sigma); - context.restore(); - debug(''); - } - } - - runTest(); - </script> -</body> -</html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script type="text/javascript" src="canvas-blending-helpers.js"></script> +<script> +test(function(t) { + var canvas = document.createElement("canvas"); + var sigma = 5; + canvas.width = 10; + canvas.height = 10; + context = canvas.getContext("2d"); + for (var i = 0; i < blendModes.length; ++i) { + context.clearRect(0, 0, 10, 10); + context.save(); + fillPathWithBackdropInContext(context); + context.globalCompositeOperation = blendModes[i]; + fillPathWithSourceInContext(context); + checkBlendModeResult(i, context, sigma); + context.restore(); + } +}, 'Series of tests to ensure correct results on applying different blend modes when drawing paths.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-global-alpha-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-global-alpha-expected.txt deleted file mode 100644 index 789dd70a..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-global-alpha-expected.txt +++ /dev/null
@@ -1,105 +0,0 @@ -Series of tests to ensure correct results on applying different blend modes when globalAlpha is set. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -Testing blend mode source-over -PASS actualColor(0, 0)[0] is within 5 of 141.6 -PASS actualColor(0, 0)[1] is within 5 of 242.4 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode multiply -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 242.4 -PASS actualColor(0, 0)[2] is within 5 of 122.62588235294116 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode screen -PASS actualColor(0, 0)[0] is within 5 of 141.6 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 135.3741176470588 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode overlay -PASS actualColor(0, 0)[0] is within 5 of 141.6 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129.14823529411763 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode darken -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 242.4 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode lighten -PASS actualColor(0, 0)[0] is within 5 of 141.6 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color-dodge -PASS actualColor(0, 0)[0] is within 5 of 141.6 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 141.6 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color-burn -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 116.69302325581394 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode hard-light -PASS actualColor(0, 0)[0] is within 5 of 141.6 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129.14823529411763 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode soft-light -PASS actualColor(0, 0)[0] is within 5 of 134.2369788002302 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129.06161151529682 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode difference -PASS actualColor(0, 0)[0] is within 5 of 128.7 -PASS actualColor(0, 0)[1] is within 5 of 242.10000000000002 -PASS actualColor(0, 0)[2] is within 5 of 116.1 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode exclusion -PASS actualColor(0, 0)[0] is within 5 of 128.7 -PASS actualColor(0, 0)[1] is within 5 of 242.10000000000002 -PASS actualColor(0, 0)[2] is within 5 of 128.84823529411764 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode hue -PASS actualColor(0, 0)[0] is within 5 of 142 -PASS actualColor(0, 0)[1] is within 5 of 248 -PASS actualColor(0, 0)[2] is within 5 of 134 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode saturation -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color -PASS actualColor(0, 0)[0] is within 5 of 142 -PASS actualColor(0, 0)[1] is within 5 of 248 -PASS actualColor(0, 0)[2] is within 5 of 134 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode luminosity -PASS actualColor(0, 0)[0] is within 5 of 125 -PASS actualColor(0, 0)[1] is within 5 of 251 -PASS actualColor(0, 0)[2] is within 5 of 125 -PASS actualColor(0, 0)[3] is within 5 of 255 - -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-global-alpha.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-global-alpha.html index 742c0342..d338b2be 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-global-alpha.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-global-alpha.html
@@ -1,49 +1,33 @@ -<!DOCTYPE HTML> -<html> -<body> - <script src="../../resources/js-test.js"></script> - <script type="text/javascript" src="canvas-blending-helpers.js"></script> - <script type="text/javascript"> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script type="text/javascript" src="canvas-blending-helpers.js"></script> - description("Series of tests to ensure correct results on applying different blend modes when globalAlpha is set."); +<script> +function checkBlendModeResult(i, context, sigma) { + var expectedColor = blendColors([129 / 255, 1, 129 / 255, 1], [1, 129 / 255, 129 / 255, 0.1], i); + var ac = context.getImageData(0, 0, 1, 1).data; + assert_approx_equals(ac[0], expectedColor[0], sigma); + assert_approx_equals(ac[1], expectedColor[1], sigma); + assert_approx_equals(ac[2], expectedColor[2], sigma); + assert_approx_equals(ac[3], expectedColor[3], sigma); +} - var context; - function actualColor(x, y) { - return context.getImageData(x, y, 1, 1).data; - } +test(function(t) { + var canvas = document.createElement("canvas"); + var sigma = 5; + canvas.width = 10; + canvas.height = 10; + context = canvas.getContext("2d"); - function checkBlendModeResult(i, context, sigma) { - var expectedColor = blendColors([129 / 255, 1, 129 / 255, 1], [1, 129 / 255, 129 / 255, 0.1], i); - var ac = "actualColor(0, 0)"; - shouldBeCloseTo(ac + "[0]", expectedColor[0], sigma); - shouldBeCloseTo(ac + "[1]", expectedColor[1], sigma); - shouldBeCloseTo(ac + "[2]", expectedColor[2], sigma); - shouldBeCloseTo(ac + "[3]", expectedColor[3], sigma); - } - - function runTest() { - var canvas = document.createElement("canvas"); - var sigma = 5; - canvas.width = 10; - canvas.height = 10; - context = canvas.getContext("2d"); - - for (var i = 0; i < blendModes.length; ++i) { - debug("Testing blend mode " + blendModes[i]); - - context.clearRect(0, 0, 10, 10); - context.save(); - drawBackdropColorInContext(context); - context.globalCompositeOperation = blendModes[i]; - context.globalAlpha = 0.1; - drawSourceColorInContext(context); - checkBlendModeResult(i, context, sigma); - context.restore(); - debug(''); - } - } - - runTest(); - </script> -</body> -</html> + for (var i = 0; i < blendModes.length; ++i) { + context.clearRect(0, 0, 10, 10); + context.save(); + drawBackdropColorInContext(context); + context.globalCompositeOperation = blendModes[i]; + context.globalAlpha = 0.1; + drawSourceColorInContext(context); + checkBlendModeResult(i, context, sigma); + context.restore(); + } +}, 'Series of tests to ensure correct results on applying different blend modes when globalAlpha is set.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-color-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-color-expected.txt deleted file mode 100644 index 55f3b1c..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-color-expected.txt +++ /dev/null
@@ -1,105 +0,0 @@ -Series of tests to ensure correct results on applying different blend modes when drawing a gradient on top of a color. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -Testing blend mode source-over -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode multiply -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 65.25882352941176 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode screen -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 192.74117647058821 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode overlay -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 130.48235294117646 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode darken -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode lighten -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color-dodge -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 255 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color-burn -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 5.930232558139517 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode hard-light -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 130.48235294117646 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode soft-light -PASS actualColor(0, 0)[0] is within 5 of 181.3697880023021 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129.61611515296823 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode difference -PASS actualColor(0, 0)[0] is within 5 of 126 -PASS actualColor(0, 0)[1] is within 5 of 126 -PASS actualColor(0, 0)[2] is within 5 of 0 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode exclusion -PASS actualColor(0, 0)[0] is within 5 of 126 -PASS actualColor(0, 0)[1] is within 5 of 126 -PASS actualColor(0, 0)[2] is within 5 of 127.48235294117649 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode hue -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 181 -PASS actualColor(0, 0)[2] is within 5 of 181 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode saturation -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 181 -PASS actualColor(0, 0)[2] is within 5 of 181 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode luminosity -PASS actualColor(0, 0)[0] is within 5 of 92 -PASS actualColor(0, 0)[1] is within 5 of 218 -PASS actualColor(0, 0)[2] is within 5 of 92 -PASS actualColor(0, 0)[3] is within 5 of 255 - -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-color.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-color.html index 1912320..c13ea1e 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-color.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-color.html
@@ -1,48 +1,21 @@ -<!DOCTYPE HTML> -<html> -<body> - <script src="../../resources/js-test.js"></script> - <script type="text/javascript" src="canvas-blending-helpers.js"></script> - <script type="text/javascript"> - - description("Series of tests to ensure correct results on applying different blend modes when drawing a gradient on top of a color."); - - var context; - function actualColor(x, y) { - return context.getImageData(x, y, 1, 1).data; - } - - function checkBlendModeResult(i, context, sigma) { - var expectedColor = blendColors([129 / 255, 1, 129 / 255, 1], [1, 129 / 255, 129 / 255, 1], i); - var ac = "actualColor(0, 0)"; - shouldBeCloseTo(ac + "[0]", expectedColor[0], sigma); - shouldBeCloseTo(ac + "[1]", expectedColor[1], sigma); - shouldBeCloseTo(ac + "[2]", expectedColor[2], sigma); - shouldBeCloseTo(ac + "[3]", expectedColor[3], sigma); - } - - function runTest() { - var canvas = document.createElement("canvas"); - var sigma = 5; - canvas.width = 10; - canvas.height = 10; - context = canvas.getContext("2d"); - - for (var i = 0; i < blendModes.length; ++i) { - debug("Testing blend mode " + blendModes[i]); - - context.clearRect(0, 0, 10, 10); - context.save(); - drawBackdropColorInContext(context); - context.globalCompositeOperation = blendModes[i]; - drawSourceColorGradientInContext(context); - checkBlendModeResult(i, context, sigma); - context.restore(); - debug(''); - } - } - - runTest(); - </script> -</body> -</html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script type="text/javascript" src="canvas-blending-helpers.js"></script> +<script> +test(function(t) { + var canvas = document.createElement('canvas'); + var sigma = 5; + canvas.width = 10; + canvas.height = 10; + context = canvas.getContext('2d'); + for (var i = 0; i < blendModes.length; ++i) { + context.clearRect(0, 0, 10, 10); + context.save(); + drawBackdropColorInContext(context); + context.globalCompositeOperation = blendModes[i]; + drawSourceColorGradientInContext(context); + checkBlendModeResult(i, context, sigma); + context.restore(); + } +}, 'Series of tests to ensure correct results on applying different blend modes when drawing a gradient on top of a color.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-gradient-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-gradient-expected.txt deleted file mode 100644 index c9f1405d..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-gradient-expected.txt +++ /dev/null
@@ -1,105 +0,0 @@ -Series of tests to ensure correct results on applying different blend modes when drawing a gradient on top of another. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -Testing blend mode source-over -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode multiply -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 65.25882352941176 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode screen -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 192.74117647058821 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode overlay -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 130.48235294117646 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode darken -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode lighten -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color-dodge -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 255 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color-burn -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 5.930232558139517 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode hard-light -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 130.48235294117646 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode soft-light -PASS actualColor(0, 0)[0] is within 5 of 181.3697880023021 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129.61611515296823 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode difference -PASS actualColor(0, 0)[0] is within 5 of 126 -PASS actualColor(0, 0)[1] is within 5 of 126 -PASS actualColor(0, 0)[2] is within 5 of 0 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode exclusion -PASS actualColor(0, 0)[0] is within 5 of 126 -PASS actualColor(0, 0)[1] is within 5 of 126 -PASS actualColor(0, 0)[2] is within 5 of 127.48235294117649 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode hue -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 181 -PASS actualColor(0, 0)[2] is within 5 of 181 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode saturation -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 181 -PASS actualColor(0, 0)[2] is within 5 of 181 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode luminosity -PASS actualColor(0, 0)[0] is within 5 of 92 -PASS actualColor(0, 0)[1] is within 5 of 218 -PASS actualColor(0, 0)[2] is within 5 of 92 -PASS actualColor(0, 0)[3] is within 5 of 255 - -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-gradient.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-gradient.html index febc087..a313cfd 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-gradient.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-gradient.html
@@ -1,48 +1,21 @@ -<!DOCTYPE HTML> -<html> -<body> - <script src="../../resources/js-test.js"></script> - <script type="text/javascript" src="canvas-blending-helpers.js"></script> - <script type="text/javascript"> - - description("Series of tests to ensure correct results on applying different blend modes when drawing a gradient on top of another."); - - var context; - function actualColor(x, y) { - return context.getImageData(x, y, 1, 1).data; - } - - function checkBlendModeResult(i, context, sigma) { - var expectedColor = blendColors([129 / 255, 1, 129 / 255, 1], [1, 129 / 255, 129 / 255, 1], i); - var ac = "actualColor(0, 0)"; - shouldBeCloseTo(ac + "[0]", expectedColor[0], sigma); - shouldBeCloseTo(ac + "[1]", expectedColor[1], sigma); - shouldBeCloseTo(ac + "[2]", expectedColor[2], sigma); - shouldBeCloseTo(ac + "[3]", expectedColor[3], sigma); - } - - function runTest() { - var canvas = document.createElement("canvas"); - var sigma = 5; - canvas.width = 10; - canvas.height = 10; - context = canvas.getContext("2d"); - - for (var i = 0; i < blendModes.length; ++i) { - debug("Testing blend mode " + blendModes[i]); - - context.clearRect(0, 0, 10, 10); - context.save(); - drawBackdropColorGradientInContext(context); - context.globalCompositeOperation = blendModes[i]; - drawSourceColorGradientInContext(context); - checkBlendModeResult(i, context, sigma); - context.restore(); - debug(''); - } - } - - runTest(); - </script> -</body> -</html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script type="text/javascript" src="canvas-blending-helpers.js"></script> +<script> +test(function(t) { + var canvas = document.createElement('canvas'); + var sigma = 5; + canvas.width = 10; + canvas.height = 10; + context = canvas.getContext('2d'); + for (var i = 0; i < blendModes.length; ++i) { + context.clearRect(0, 0, 10, 10); + context.save(); + drawBackdropColorGradientInContext(context); + context.globalCompositeOperation = blendModes[i]; + drawSourceColorGradientInContext(context); + checkBlendModeResult(i, context, sigma); + context.restore(); + } +}, 'Series of tests to ensure correct results on applying different blend modes when drawing a gradient on top of another.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-image-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-image-expected.txt deleted file mode 100644 index b914fc8..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-image-expected.txt +++ /dev/null
@@ -1,105 +0,0 @@ -Series of tests to ensure correct results on applying different blend modes when drawing a gradient on top of an image. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -Testing blend mode source-over -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode multiply -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 65.25882352941176 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode screen -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 192.74117647058821 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode overlay -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 130.48235294117646 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode darken -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode lighten -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color-dodge -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 255 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color-burn -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 5.930232558139517 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode hard-light -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 130.48235294117646 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode soft-light -PASS actualColor(0, 0)[0] is within 5 of 181.3697880023021 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129.61611515296823 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode difference -PASS actualColor(0, 0)[0] is within 5 of 126 -PASS actualColor(0, 0)[1] is within 5 of 126 -PASS actualColor(0, 0)[2] is within 5 of 0 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode exclusion -PASS actualColor(0, 0)[0] is within 5 of 126 -PASS actualColor(0, 0)[1] is within 5 of 126 -PASS actualColor(0, 0)[2] is within 5 of 127.48235294117649 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode hue -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 181 -PASS actualColor(0, 0)[2] is within 5 of 181 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode saturation -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 181 -PASS actualColor(0, 0)[2] is within 5 of 181 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode luminosity -PASS actualColor(0, 0)[0] is within 5 of 92 -PASS actualColor(0, 0)[1] is within 5 of 218 -PASS actualColor(0, 0)[2] is within 5 of 92 -PASS actualColor(0, 0)[3] is within 5 of 255 - -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-image.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-image.html index 0c2309b2..4d181c96 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-image.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-image.html
@@ -1,63 +1,28 @@ -<!DOCTYPE HTML> -<html> -<head> - <script type="text/javascript"> - if (window.testRunner) - testRunner.waitUntilDone(); - window.jsTestIsAsync = true - </script> -</head> -<body> - <script src="../../resources/js-test.js"></script> - <script type="text/javascript" src="canvas-blending-helpers.js"></script> - <script type="text/javascript"> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script type="text/javascript" src="canvas-blending-helpers.js"></script> +<script> +function drawElement(context, i) { + if (i >= blendModes.length) + return; + context.clearRect(0, 0, 10, 10); + context.save(); + drawBackdropColorImageInContext(context, + function() { + context.globalCompositeOperation = blendModes[i]; + drawSourceColorGradientInContext(context); + checkBlendModeResult(i, context, 5); + context.restore(); + drawElement(context, ++i); + }); +} - description("Series of tests to ensure correct results on applying different blend modes when drawing a gradient on top of an image."); - - var context; - function actualColor(x, y) { - return context.getImageData(x, y, 1, 1).data; - } - - function checkBlendModeResult(i, context, sigma) { - var expectedColor = blendColors([129 / 255, 1, 129 / 255, 1], [1, 129 / 255, 129 / 255, 1], i); - var ac = "actualColor(0, 0)"; - shouldBeCloseTo(ac + "[0]", expectedColor[0], sigma); - shouldBeCloseTo(ac + "[1]", expectedColor[1], sigma); - shouldBeCloseTo(ac + "[2]", expectedColor[2], sigma); - shouldBeCloseTo(ac + "[3]", expectedColor[3], sigma); - } - - function drawElement(context, i) { - if (i >= blendModes.length) { - finishJSTest(); - return; - } - debug("Testing blend mode " + blendModes[i]); - - context.clearRect(0, 0, 10, 10); - context.save(); - drawBackdropColorImageInContext(context, - function() { - context.globalCompositeOperation = blendModes[i]; - drawSourceColorGradientInContext(context); - checkBlendModeResult(i, context, 5); - context.restore(); - debug(''); - drawElement(context, ++i); - }); - } - - function runTest() { - var canvas = document.createElement("canvas"); - var sigma = 5; - canvas.width = 10; - canvas.height = 10; - context = canvas.getContext("2d"); - drawElement(context, 0); - } - - runTest(); - </script> -</body> -</html> +test(function(t) { + var canvas = document.createElement('canvas'); + var sigma = 5; + canvas.width = 10; + canvas.height = 10; + context = canvas.getContext('2d'); + drawElement(context, 0); +}, 'Series of tests to ensure correct results on applying different blend modes when drawing a gradient on top of an image.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-pattern-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-pattern-expected.txt deleted file mode 100644 index 296fdd9..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-pattern-expected.txt +++ /dev/null
@@ -1,105 +0,0 @@ -Series of tests to ensure correct results on applying different blend modes when drawing a gradient on top of an pattern. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -Testing blend mode source-over -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode multiply -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 65.25882352941176 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode screen -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 192.74117647058821 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode overlay -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 130.48235294117646 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode darken -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 129 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode lighten -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color-dodge -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 255 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color-burn -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 5.930232558139517 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode hard-light -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 130.48235294117646 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode soft-light -PASS actualColor(0, 0)[0] is within 5 of 181.3697880023021 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129.61611515296823 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode difference -PASS actualColor(0, 0)[0] is within 5 of 126 -PASS actualColor(0, 0)[1] is within 5 of 126 -PASS actualColor(0, 0)[2] is within 5 of 0 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode exclusion -PASS actualColor(0, 0)[0] is within 5 of 126 -PASS actualColor(0, 0)[1] is within 5 of 126 -PASS actualColor(0, 0)[2] is within 5 of 127.48235294117649 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode hue -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 181 -PASS actualColor(0, 0)[2] is within 5 of 181 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode saturation -PASS actualColor(0, 0)[0] is within 5 of 129 -PASS actualColor(0, 0)[1] is within 5 of 255 -PASS actualColor(0, 0)[2] is within 5 of 129 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode color -PASS actualColor(0, 0)[0] is within 5 of 255 -PASS actualColor(0, 0)[1] is within 5 of 181 -PASS actualColor(0, 0)[2] is within 5 of 181 -PASS actualColor(0, 0)[3] is within 5 of 255 - -Testing blend mode luminosity -PASS actualColor(0, 0)[0] is within 5 of 92 -PASS actualColor(0, 0)[1] is within 5 of 218 -PASS actualColor(0, 0)[2] is within 5 of 92 -PASS actualColor(0, 0)[3] is within 5 of 255 - -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-pattern.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-pattern.html index 104de61c..3b704c7 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-pattern.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-gradient-over-pattern.html
@@ -1,63 +1,29 @@ -<!DOCTYPE HTML> -<html> -<head> - <script type="text/javascript"> - if (window.testRunner) - testRunner.waitUntilDone(); - window.jsTestIsAsync = true - </script> -</head> -<body> - <script src="../../resources/js-test.js"></script> - <script type="text/javascript" src="canvas-blending-helpers.js"></script> - <script type="text/javascript"> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script type="text/javascript" src="canvas-blending-helpers.js"></script> +<script> +function drawElement(context, i) { + if (i >= blendModes.length) + return; + context.clearRect(0, 0, 10, 10); + context.save(); + drawBackdropColorPatternInContext(context, + function() { + context.globalCompositeOperation = blendModes[i]; + drawSourceColorGradientInContext(context); + checkBlendModeResult(i, context, 5); + context.restore(); + drawElement(context, ++i); + }); +} - description("Series of tests to ensure correct results on applying different blend modes when drawing a gradient on top of an pattern."); +test(function(t) { + var canvas = document.createElement('canvas'); + var sigma = 5; + canvas.width = 10; + canvas.height = 10; + context = canvas.getContext('2d'); + drawElement(context, 0); - var context; - function actualColor(x, y) { - return context.getImageData(x, y, 1, 1).data; - } - - function checkBlendModeResult(i, context, sigma) { - var expectedColor = blendColors([129 / 255, 1, 129 / 255, 1], [1, 129 / 255, 129 / 255, 1], i); - var ac = "actualColor(0, 0)"; - shouldBeCloseTo(ac + "[0]", expectedColor[0], sigma); - shouldBeCloseTo(ac + "[1]", expectedColor[1], sigma); - shouldBeCloseTo(ac + "[2]", expectedColor[2], sigma); - shouldBeCloseTo(ac + "[3]", expectedColor[3], sigma); - } - - function drawElement(context, i) { - if (i >= blendModes.length) { - finishJSTest(); - return; - } - debug("Testing blend mode " + blendModes[i]); - - context.clearRect(0, 0, 10, 10); - context.save(); - drawBackdropColorPatternInContext(context, - function() { - context.globalCompositeOperation = blendModes[i]; - drawSourceColorGradientInContext(context); - checkBlendModeResult(i, context, 5); - context.restore(); - debug(''); - drawElement(context, ++i); - }); - } - - function runTest() { - var canvas = document.createElement("canvas"); - var sigma = 5; - canvas.width = 10; - canvas.height = 10; - context = canvas.getContext("2d"); - drawElement(context, 0); - } - - runTest(); - </script> -</body> -</html> +}, 'Series of tests to ensure correct results on applying different blend modes when drawing a gradient on top of an pattern.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-helpers.js b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-helpers.js index ff34874..af2885c0 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-helpers.js +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-blending-helpers.js
@@ -300,3 +300,12 @@ expectedColor[i] = source[3] * (1 - backdrop[3]) * source[i] + source[3] * backdrop[3] * expectedColor[i] + (1 - source[3]) * backdrop[3] * backdrop[i]; return [Math.round(255 * expectedColor[0]), Math.round(255 * expectedColor[1]), Math.round(255 * expectedColor[2]), 255]; } + +function checkBlendModeResult(i, context, sigma) { + var actualColor = context.getImageData(0, 0, 1, 1).data; + var expectedColor = blendColors([129 / 255, 1, 129 / 255, 1], [1, 129 / 255, 129 / 255, 1], i); + assert_approx_equals(actualColor[0], expectedColor[0], sigma); + assert_approx_equals(actualColor[1], expectedColor[1], sigma); + assert_approx_equals(actualColor[2], expectedColor[2], sigma); + assert_approx_equals(actualColor[3], expectedColor[3], sigma); +}
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-frameless-document-text-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-frameless-document-text-expected.txt deleted file mode 100644 index 5c3f90595..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-frameless-document-text-expected.txt +++ /dev/null
@@ -1,9 +0,0 @@ -This verifies that the browser does not crash when drawing text to a canvas in a frame-less document. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-frameless-document-text.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-frameless-document-text.html index c18bd501f..cdecc0f 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-frameless-document-text.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-frameless-document-text.html
@@ -1,9 +1,28 @@ -<!DOCTYPE HTML> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <body> -<script src="script-tests/canvas-frameless-document-text.js"></script> +<script> +test(function(t) { + + // It is not clear from the spec whether this is supposed to work and how. + // Therefore, we do not validate the rendering results. We just make sure + // this does not crash the browser. + var canvas1 = document.createElement('canvas'); + var ctx1 = canvas1.getContext('2d'); + var htmlDoc = document.implementation.createHTMLDocument('', '', null); + htmlDoc.adoptNode(canvas1); + var canvas2 = htmlDoc.createElement('canvas'); + var ctx2 = canvas2.getContext('2d'); + + ctx1.font = 'italic 30px Arial'; + ctx2.font = 'italic 30px Arial'; + ctx1.fillText('Text1', 0, 30); + ctx2.fillText('Text1', 0, 30); + ctx1.strokeText('Text2', 0, 60); + ctx2.strokeText('Text2', 0, 60); + ctx1.measureText('Text3'); + ctx2.measureText('Text3'); + +}, "This verifies that the browser does not crash when drawing text to a canvas in a frame-less document."); +</script> </body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getContext-invalid-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getContext-invalid-expected.txt deleted file mode 100644 index 96c5b7c..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getContext-invalid-expected.txt +++ /dev/null
@@ -1,18 +0,0 @@ -Test that invalid canvas getContext() requests return null. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS canvas.getContext('') is null -PASS canvas.getContext('2d#') is null -PASS canvas.getContext('This is clearly not a valid context name.') is null -PASS canvas.getContext('2d\0') is null -PASS canvas.getContext('2d') is null -PASS canvas.getContext('2D') is null -PASS canvas.getContext() threw exception TypeError: Failed to execute 'getContext' on 'HTMLCanvasElement': 1 argument required, but only 0 present.. -PASS canvas.getContext('null') is null -PASS canvas.getContext('undefined') is null -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getContext-invalid.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getContext-invalid.html index 088055d..cf7aad2f 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getContext-invalid.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getContext-invalid.html
@@ -1,9 +1,20 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <body> -<script src="script-tests/canvas-getContext-invalid.js"></script> +<script> +test(function(t) { + canvas = document.createElement('canvas'); + + assert_equals(canvas.getContext(''), null); + assert_equals(canvas.getContext('2d#'), null); + assert_equals(canvas.getContext('This is clearly not a valid context name.'), null); + assert_equals(canvas.getContext('2d\0'), null); + assert_equals(canvas.getContext('2\uFF44'), null); + assert_equals(canvas.getContext('2D'), null); + assert_throws(null, function() {canvas.getContext();}); + assert_equals(canvas.getContext('null'), null); + assert_equals(canvas.getContext('undefined'), null); + +}, "Test that invalid canvas getContext() requests return null."); +</script> </body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-expected.txt deleted file mode 100644 index d399a72..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-expected.txt +++ /dev/null
@@ -1,30 +0,0 @@ -This test ensures that getImageData works correctly. -PASS: pixel at (0,0) was [0,0,0,255] -PASS: pixel at (4,0) was [0,11,0,255] -PASS: pixel at (8,0) was [0,21,0,255] -PASS: pixel at (12,0) was [0,32,0,255] -PASS: pixel at (16,0) was [0,43,0,255] -PASS: pixel at (20,0) was [0,53,0,255] -PASS: pixel at (24,0) was [0,64,0,255] -PASS: pixel at (28,0) was [0,74,0,255] -PASS: pixel at (32,0) was [0,85,0,255] -PASS: pixel at (36,0) was [0,96,0,255] -PASS: pixel at (40,0) was [0,106,0,255] -PASS: pixel at (44,0) was [0,117,0,255] -PASS: pixel at (48,0) was [0,128,0,255] -PASS: pixel at (52,0) was [0,138,0,255] -PASS: pixel at (56,0) was [0,149,0,255] -PASS: pixel at (60,0) was [0,159,0,255] -PASS: pixel at (64,0) was [0,170,0,255] -PASS: pixel at (68,0) was [0,181,0,255] -PASS: pixel at (72,0) was [0,191,0,255] -PASS: pixel at (76,0) was [0,202,0,255] -PASS: pixel at (80,0) was [0,213,0,255] -PASS: pixel at (84,0) was [0,223,0,255] -PASS: pixel at (88,0) was [0,234,0,255] -PASS: pixel at (92,0) was [0,244,0,255] -PASS: pixel at (96,0) was [0,255,0,255] -PASS: pixel at (5,5) was [64,128,191,255] -PASS: Correctly retrieved every pixel in a row -PASS: Correct data for content outside canvas bounds -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-invalid-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-invalid-expected.txt deleted file mode 100644 index f61dec2..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-invalid-expected.txt +++ /dev/null
@@ -1,23 +0,0 @@ -Test the handling of invalid arguments in canvas getImageData(). - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS ctx.getImageData(NaN, 10, 10, 10) threw exception TypeError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.getImageData(10, NaN, 10, 10) threw exception TypeError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.getImageData(10, 10, NaN, 10) threw exception TypeError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.getImageData(10, 10, 10, NaN) threw exception TypeError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.getImageData(Infinity, 10, 10, 10) threw exception TypeError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.getImageData(10, Infinity, 10, 10) threw exception TypeError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.getImageData(10, 10, Infinity, 10) threw exception TypeError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.getImageData(10, 10, 10, Infinity) threw exception TypeError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.getImageData(undefined, 10, 10, 10) threw exception TypeError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.getImageData(10, undefined, 10, 10) threw exception TypeError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.getImageData(10, 10, undefined, 10) threw exception TypeError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.getImageData(10, 10, 10, undefined) threw exception TypeError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.getImageData(10, 10, 0, 10) threw exception IndexSizeError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The source width is 0.. -PASS ctx.getImageData(10, 10, 10, 0) threw exception IndexSizeError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The source height is 0.. -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-invalid.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-invalid.html index aeb17ea..83030de 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-invalid.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-invalid.html
@@ -1,9 +1,24 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <body> -<script src="script-tests/canvas-getImageData-invalid.js"></script> +<script> +test(function(t) { + ctx = document.createElement('canvas').getContext('2d'); + + assert_throws(null, function() {ctx.getImageData(NaN, 10, 10, 10)}); + assert_throws(null, function() {ctx.getImageData(10, NaN, 10, 10)}); + assert_throws(null, function() {ctx.getImageData(10, 10, NaN, 10)}); + assert_throws(null, function() {ctx.getImageData(10, 10, 10, NaN)}); + assert_throws(null, function() {ctx.getImageData(Infinity, 10, 10, 10)}); + assert_throws(null, function() {ctx.getImageData(10, Infinity, 10, 10)}); + assert_throws(null, function() {ctx.getImageData(10, 10, Infinity, 10)}); + assert_throws(null, function() {ctx.getImageData(10, 10, 10, Infinity)}); + assert_throws(null, function() {ctx.getImageData(undefined, 10, 10, 10)}); + assert_throws(null, function() {ctx.getImageData(10, undefined, 10, 10)}); + assert_throws(null, function() {ctx.getImageData(10, 10, undefined, 10)}); + assert_throws(null, function() {ctx.getImageData(10, 10, 10, undefined)}); + assert_throws(null, function() {ctx.getImageData(10, 10, 0, 10)}); + assert_throws(null, function() {ctx.getImageData(10, 10, 10, 0)}); +}, "Test the handling of invalid arguments in canvas getImageData()."); +</script> </body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-large-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-large-crash-expected.txt deleted file mode 100644 index 30b54bd..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-large-crash-expected.txt +++ /dev/null
@@ -1 +0,0 @@ -PASSED (If this page did not crash.)
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-large-crash.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-large-crash.html index c9e69cd68..61bb9209 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-large-crash.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-large-crash.html
@@ -1,14 +1,8 @@ -<html> -<head> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <script> -if (window.testRunner) - testRunner.dumpAsText(); - -var canvas = document.createElement("canvas"); -canvas.getContext("2d").getImageData(10, 0xffffffff, 2147483647,10); +test(function(t) { + var canvas = document.createElement("canvas"); + canvas.getContext("2d").getImageData(10, 0xffffffff, 2147483647,10); +}, 'Test that canvas does not crash when large image data is requested.'); </script> -</head> -<body> -PASSED (If this page did not crash.) -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-largeNonintegralDimensions-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-largeNonintegralDimensions-expected.txt deleted file mode 100644 index 1853caa7..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-largeNonintegralDimensions-expected.txt +++ /dev/null
@@ -1 +0,0 @@ -PASS!
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-largeNonintegralDimensions.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-largeNonintegralDimensions.html index 5ce9293..c9aa99e 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-largeNonintegralDimensions.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-largeNonintegralDimensions.html
@@ -1,11 +1,10 @@ -<html> -PASS! -<script> -if (window.testRunner) - window.testRunner.dumpAsText(); +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> -var canvas = document.createElement("canvas"); -var ctx = canvas.getContext("2d"); -ctx.getImageData(100.5, 2147483647.5, -2048.5, -2048.5); +<script> +test(function(t) { + var canvas = document.createElement("canvas"); + var ctx = canvas.getContext("2d"); + ctx.getImageData(100.5, 2147483647.5, -2048.5, -2048.5); +}, 'Test that canvas does not crash when large negative dimensions is asked for the image data.'); </script> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-negative-source-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-negative-source-expected.txt deleted file mode 100644 index f8a6b1e0..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-negative-source-expected.txt +++ /dev/null
@@ -1,21 +0,0 @@ -Test the handling of negative sourceRect offset in getImageData(). - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS imgdata[0] is 0 -PASS imgdata[1] is 0 -PASS imgdata[2] is 0 -PASS imgdata[3] is 0 -PASS imgdata[60] is 0 -PASS imgdata[61] is 128 -PASS imgdata[62] is 0 -PASS imgdata[63] is 255 -PASS imgdata[64] is 255 -PASS imgdata[65] is 0 -PASS imgdata[66] is 0 -PASS imgdata[67] is 255 -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-negative-source.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-negative-source.html index cd22889..7aff9cb 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-negative-source.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-negative-source.html
@@ -1,9 +1,35 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <body> -<script src="script-tests/canvas-getImageData-negative-source.js"></script> +<script> +test(function(t) { + ctx = document.createElement('canvas').getContext('2d'); + + ctx.fillStyle = 'red'; + ctx.fillRect(0, 0, 100, 100); + ctx.fillStyle = 'green'; + ctx.fillRect(0, 0, 6, 6); + + var imageData = ctx.getImageData(-10, 0, 100, 1); + var imgdata = imageData.data; + + // Fully transparent black + assert_equals(imgdata[0], 0); + assert_equals(imgdata[1], 0); + assert_equals(imgdata[2], 0); + assert_equals(imgdata[3], 0); + + // Green + assert_equals(imgdata[60], 0); + assert_equals(imgdata[61], 128); + assert_equals(imgdata[62], 0); + assert_equals(imgdata[63], 255); + + // Red + assert_equals(imgdata[64], 255); + assert_equals(imgdata[65], 0); + assert_equals(imgdata[66], 0); + assert_equals(imgdata[67], 255); +}, "Test the handling of negative sourceRect offset in getImageData()."); +</script> </body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-p3.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-p3.html index 73e48fd..955f989 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-p3.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-p3.html
@@ -7,38 +7,37 @@ test(putThenGetImageData, 'verifies that putImageData works on P3 canvases.'); function drawThenGetImageData() { - var canvas = document.createElement('canvas'); - canvas.width = 10; - canvas.height = 10; - var ctx = canvas.getContext('2d', {colorSpace: 'p3'}) - ctx.fillStyle = 'rgb(50, 100, 150)'; - ctx.fillRect(0, 0, 10, 10); - var pixel = ctx.getImageData(5, 5, 1, 1).data; - // Note: the color specified as as fillStyle is converted from srgb to linear - // when drawn and the the results of getImageData are re-converted to sRGB - assert_equals(pixel[0], 50, "Red component retrieved by getImageData is the color that was drawn." ); - assert_equals(pixel[1], 100, "Green component retrieved by getImageData is the color that was drawn." ); - assert_equals(pixel[2], 150, "Blue component retrieved by getImageData is the color that was drawn." ); - assert_equals(pixel[3], 255, "Alpha component retrieved by getImageData is the color that was drawn." ); + var canvas = document.createElement('canvas'); + canvas.width = 10; + canvas.height = 10; + var ctx = canvas.getContext('2d', {colorSpace: 'p3'}) + ctx.fillStyle = 'rgb(50, 100, 150)'; + ctx.fillRect(0, 0, 10, 10); + var pixel = ctx.getImageData(5, 5, 1, 1).data; + // Note: the color specified as as fillStyle is converted from srgb to linear + // when drawn and the the results of getImageData are re-converted to sRGB + assert_equals(pixel[0], 50, "Red component retrieved by getImageData is the color that was drawn." ); + assert_equals(pixel[1], 100, "Green component retrieved by getImageData is the color that was drawn." ); + assert_equals(pixel[2], 150, "Blue component retrieved by getImageData is the color that was drawn." ); + assert_equals(pixel[3], 255, "Alpha component retrieved by getImageData is the color that was drawn." ); } function putThenGetImageData() { - var canvas = document.createElement('canvas'); - canvas.width = 10; - canvas.height = 10; - var ctx = canvas.getContext('2d', {colorSpace: 'p3'}) - var initialData = ctx.createImageData(1, 1); - initialData.data[0] = 50; - initialData.data[1] = 100; - initialData.data[2] = 150; - initialData.data[3] = 255; - ctx.putImageData(initialData, 5, 5); - var pixel = ctx.getImageData(5, 5, 1, 1).data; - assert_equals(pixel[0], 50, "Red component retrieved by getImageData is the color that was put." ); - assert_equals(pixel[1], 100, "Green component retrieved by getImageData is the color that was put." ); - assert_equals(pixel[2], 150, "Blue component retrieved by getImageData is the color that was put." ); - assert_equals(pixel[3], 255, "Alpha component retrieved by getImageData is the color that was put." ); + var canvas = document.createElement('canvas'); + canvas.width = 10; + canvas.height = 10; + var ctx = canvas.getContext('2d', {colorSpace: 'p3'}) + var initialData = ctx.createImageData(1, 1); + initialData.data[0] = 50; + initialData.data[1] = 100; + initialData.data[2] = 150; + initialData.data[3] = 255; + ctx.putImageData(initialData, 5, 5); + var pixel = ctx.getImageData(5, 5, 1, 1).data; + assert_equals(pixel[0], 50, "Red component retrieved by getImageData is the color that was put." ); + assert_equals(pixel[1], 100, "Green component retrieved by getImageData is the color that was put." ); + assert_equals(pixel[2], 150, "Blue component retrieved by getImageData is the color that was put." ); + assert_equals(pixel[3], 255, "Alpha component retrieved by getImageData is the color that was put." ); } - </script> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-rec-2020.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-rec-2020.html index 173cc3d..b89fd39b 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-rec-2020.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-rec-2020.html
@@ -7,38 +7,37 @@ test(putThenGetImageData, 'verifies that putImageData works on rec-2020 canvases.'); function drawThenGetImageData() { - var canvas = document.createElement('canvas'); - canvas.width = 10; - canvas.height = 10; - var ctx = canvas.getContext('2d', {colorSpace: 'rec-2020'}) - ctx.fillStyle = 'rgb(50, 100, 150)'; - ctx.fillRect(0, 0, 10, 10); - var pixel = ctx.getImageData(5, 5, 1, 1).data; - // Note: the color specified as as fillStyle is converted from srgb to linear - // when drawn and the the results of getImageData are re-converted to sRGB - assert_equals(pixel[0], 50, "Red component retrieved by getImageData is the color that was drawn." ); - assert_equals(pixel[1], 100, "Green component retrieved by getImageData is the color that was drawn." ); - assert_equals(pixel[2], 150, "Blue component retrieved by getImageData is the color that was drawn." ); - assert_equals(pixel[3], 255, "Alpha component retrieved by getImageData is the color that was drawn." ); + var canvas = document.createElement('canvas'); + canvas.width = 10; + canvas.height = 10; + var ctx = canvas.getContext('2d', {colorSpace: 'rec-2020'}) + ctx.fillStyle = 'rgb(50, 100, 150)'; + ctx.fillRect(0, 0, 10, 10); + var pixel = ctx.getImageData(5, 5, 1, 1).data; + // Note: the color specified as as fillStyle is converted from srgb to linear + // when drawn and the the results of getImageData are re-converted to sRGB + assert_equals(pixel[0], 50, "Red component retrieved by getImageData is the color that was drawn." ); + assert_equals(pixel[1], 100, "Green component retrieved by getImageData is the color that was drawn." ); + assert_equals(pixel[2], 150, "Blue component retrieved by getImageData is the color that was drawn." ); + assert_equals(pixel[3], 255, "Alpha component retrieved by getImageData is the color that was drawn." ); } function putThenGetImageData() { - var canvas = document.createElement('canvas'); - canvas.width = 10; - canvas.height = 10; - var ctx = canvas.getContext('2d', {colorSpace: 'rec-2020'}) - var initialData = ctx.createImageData(1, 1); - initialData.data[0] = 50; - initialData.data[1] = 100; - initialData.data[2] = 150; - initialData.data[3] = 255; - ctx.putImageData(initialData, 5, 5); - var pixel = ctx.getImageData(5, 5, 1, 1).data; - assert_equals(pixel[0], 50, "Red component retrieved by getImageData is the color that was put." ); - assert_equals(pixel[1], 100, "Green component retrieved by getImageData is the color that was put." ); - assert_equals(pixel[2], 150, "Blue component retrieved by getImageData is the color that was put." ); - assert_equals(pixel[3], 255, "Alpha component retrieved by getImageData is the color that was put." ); + var canvas = document.createElement('canvas'); + canvas.width = 10; + canvas.height = 10; + var ctx = canvas.getContext('2d', {colorSpace: 'rec-2020'}) + var initialData = ctx.createImageData(1, 1); + initialData.data[0] = 50; + initialData.data[1] = 100; + initialData.data[2] = 150; + initialData.data[3] = 255; + ctx.putImageData(initialData, 5, 5); + var pixel = ctx.getImageData(5, 5, 1, 1).data; + assert_equals(pixel[0], 50, "Red component retrieved by getImageData is the color that was put." ); + assert_equals(pixel[1], 100, "Green component retrieved by getImageData is the color that was put." ); + assert_equals(pixel[2], 150, "Blue component retrieved by getImageData is the color that was put." ); + assert_equals(pixel[3], 255, "Alpha component retrieved by getImageData is the color that was put." ); } - </script> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-rounding-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-rounding-expected.txt deleted file mode 100644 index e7ea28bb..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-rounding-expected.txt +++ /dev/null
@@ -1,36 +0,0 @@ -Test the handling of non-integer source coordinates in getImageData(). - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -getImageData(0, 0, 20, 10) -PASS imageData.width is 20 -PASS imageData.height is 10 -getImageData(0.1, 0.2, 20, 10) -PASS imageData.width is 21 -PASS imageData.height is 11 -getImageData(0.9, 0.8, 20, 10) -PASS imageData.width is 21 -PASS imageData.height is 11 -getImageData(0, 0, 19.9, 9.9) -PASS imageData.width is 20 -PASS imageData.height is 10 -getImageData(0, 0, 19.1, 9.1) -PASS imageData.width is 20 -PASS imageData.height is 10 -getImageData(0.9, 0, 0.2, 10) -PASS imageData.width is 2 -PASS imageData.height is 10 -getImageData(-1, -1, 20, 10) -PASS imageData.width is 20 -PASS imageData.height is 10 -getImageData(-1.1, 0, 20, 10) -PASS imageData.width is 21 -PASS imageData.height is 10 -getImageData(-1.9, 0, 20, 10) -PASS imageData.width is 21 -PASS imageData.height is 10 -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-rounding.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-rounding.html index a2d93f9e..fa1766c 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-rounding.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData-rounding.html
@@ -1,42 +1,37 @@ -<!DOCTYPE html> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <body> <script> -description("Test the handling of non-integer source coordinates in getImageData()."); - -ctx = document.createElement('canvas').getContext('2d'); - -function dimensionsShouldBe(sx, sy, sw, sh, width, height) -{ - imageData = ctx.getImageData(sx, sy, sw, sh); - debug('getImageData(' + sx + ', ' + sy + ', ' + sw + ', ' + sh + ')'); - shouldBe('imageData.width', width + ''); - shouldBe('imageData.height', height + ''); -} - -// Basic integer values -dimensionsShouldBe( 0, 0, 20, 10, 20, 10); - -// Source point is not an integer -dimensionsShouldBe( .1, .2, 20, 10, 21, 11); -dimensionsShouldBe( .9, .8, 20, 10, 21, 11); - -// Size is not an integer -dimensionsShouldBe( 0, 0, 19.9, 9.9, 20, 10); -dimensionsShouldBe( 0, 0, 19.1, 9.1, 20, 10); - -// Width straddles a pixel boundary -dimensionsShouldBe( .9, 0, .2, 10, 2, 10); - -// Basic integer negative values -dimensionsShouldBe( -1, -1, 20, 10, 20, 10); - -// Non-integer negative values -dimensionsShouldBe(-1.1, 0, 20, 10, 21, 10); -dimensionsShouldBe(-1.9, 0, 20, 10, 21, 10); +test(function(t) { + ctx = document.createElement('canvas').getContext('2d'); + + function testDimensions(sx, sy, sw, sh, width, height) + { + imageData = ctx.getImageData(sx, sy, sw, sh); + assert_equals(imageData.width, width); + assert_equals(imageData.height, height); + } + + // Basic integer values + testDimensions( 0, 0, 20, 10, 20, 10); + + // Source point is not an integer + testDimensions( .1, .2, 20, 10, 21, 11); + testDimensions( .9, .8, 20, 10, 21, 11); + + // Size is not an integer + testDimensions( 0, 0, 19.9, 9.9, 20, 10); + testDimensions( 0, 0, 19.1, 9.1, 20, 10); + + // Width straddles a pixel boundary + testDimensions( .9, 0, .2, 10, 2, 10); + + // Basic integer negative values + testDimensions( -1, -1, 20, 10, 20, 10); + + // Non-integer negative values + testDimensions(-1.1, 0, 20, 10, 21, 10); + testDimensions(-1.9, 0, 20, 10, 21, 10); +}, 'Test the handling of non-integer source coordinates in getImageData().'); </script> </body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData.html index 2a407f2..f08d044 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-getImageData.html
@@ -1,18 +1,13 @@ -This test ensures that getImageData works correctly. -<div id="log"></div> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> + <script> -if (window.testRunner) - testRunner.dumpAsText(); var canvas = document.createElement("canvas"); canvas.width = 200; canvas.height = 200; var context = canvas.getContext("2d"); -function log(msg){ - document.getElementById("log").innerHTML += msg + "<br/>"; -} - function dataToArray(data) { var result = new Array(data.length) for (var i = 0; i < data.length; i++) @@ -22,77 +17,60 @@ function getPixel(ctx, x, y) { var data = ctx.getImageData(x,y,1,1); - if (!data) // getImageData failed, which should never happen - return [-1,-1,-1,-1]; + assert_not_equals(data, null); return dataToArray(data.data); } function pixelShouldBe(ctx, x, y, colour) { var ctxColour = getPixel(ctx, x, y); - var correct = true; for (var i = 0; i < 4; i++) - if (colour[i] != ctxColour[i]) { - correct = false; + assert_equals(colour[i], ctxColour[i]); +} + +test(function(t) { + + if (!context.setFillColor) + context.setFillColor = function(r,g,b,a) { + this.fillStyle = "rgba("+[Math.round(r*255),Math.round(g*255),Math.round(b*255),Math.round(a*255)]+")"; + } + + // Check that getImageData is return the data for the right portion of the image + for(var x = 0; x < 100; x += 4) { + context.setFillColor(0, x/96, 0, 1); + context.fillRect(x, 0, 1, 1); + pixelShouldBe(context, x, 0, [0, Math.round(255*x/96), 0, 255]); + } + + // Check rgba ordering + context.clearRect(0, 0, 100, 100); + context.setFillColor(0.25, 0.5, 0.75, 1); + context.fillRect(5, 5, 1, 1); + pixelShouldBe(context, 5, 5, [Math.round(0.25*255), Math.round(0.5*255), Math.round(0.75*255), 255]); + + // Make sure we return correct values for the row + for (var i = 0; i < 100; i++) { + context.fillStyle = "rgba("+[0, i, 0, 1]+")"; + context.fillRect(i, 10, 1, 1); + } + + var rowImageData = context.getImageData(0, 10, 100, 1).data; + var rowCheck = true; + for (var i = 0; i < 100; i++) { + if (rowImageData[i * 4 + 1] != i) { + rowCheck = false; break; } - if (correct) - log("PASS: pixel at ("+[x,y]+") was ["+colour+"]"); - else - log("FAIL: pixel at ("+[x,y]+") was ["+ctxColour+"], expected ["+colour+"]"); -} - -if (!context.setFillColor) - context.setFillColor = function(r,g,b,a) { - this.fillStyle = "rgba("+[Math.round(r*255),Math.round(g*255),Math.round(b*255),Math.round(a*255)]+")" } + assert_true(rowCheck); + + // Check that we return transparent black for regions outside the canvas proper + context.fillStyle = "rgba(255,255,255,255)"; + context.fillRect(198, 5, 4, 1); // final 2 pixels horizontally should be clipped + var content = dataToArray(context.getImageData(198, 5, 4, 1).data); + var expected = [255,255,255,255,255,255,255,255, + 0,0,0,0,0,0,0,0]; + for (var i = 0; i < 16; i++) + assert_equals(content[i], expected[i]); -// Check that getImageData is return the data for the right portion of the image -for(var x = 0; x < 100; x+=4) { - context.setFillColor(0, x/96, 0, 1); - context.fillRect(x,0,1,1); - pixelShouldBe(context, x, 0, [0, Math.round(255*x/96), 0, 255]); -} - -// Check rgba ordering -context.clearRect(0,0,100,100); -context.setFillColor(0.25, 0.5, 0.75, 1); -context.fillRect(5,5,1,1); -pixelShouldBe(context, 5, 5, [Math.round(0.25*255), Math.round(0.5*255), Math.round(0.75*255), 255]); - -// Make sure we return correct values for the row -for (var i = 0; i < 100; i++) { - context.fillStyle = "rgba("+[0, i, 0, 1]+")"; - context.fillRect(i, 10, 1, 1); -} - -var rowImageData = context.getImageData(0, 10, 100, 1).data; -var rowCheck = true; -for (var i = 0; i < 100; i++) { - if (rowImageData[i * 4 + 1] != i) { - rowCheck = false; - break; - } -} -if (!rowCheck) - log("FAIL: Did not correctly retrieve every pixel in a row"); -else - log("PASS: Correctly retrieved every pixel in a row"); - -// Check that we return transparent black for regions outside the canvas proper -context.fillStyle = "rgba(255,255,255,255)"; -context.fillRect(198, 5, 4, 1); // final 2 pixels horizontally should be clipped -var content = dataToArray(context.getImageData(198, 5, 4, 1).data); -var expected = [255,255,255,255,255,255,255,255, - 0,0,0,0,0,0,0,0]; -var matched = true; -for (var i = 0; i < 16; i++) - if (content[i] != expected[i]) { - matched = false; - break; - } -if (matched) - log("PASS: Correct data for content outside canvas bounds"); -else - log("FAIL: Did not get correct data for content outside canvas bounds: "+content); - +}, 'This test ensures that getImageData works correctly.'); </script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-gradient-without-path-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-gradient-without-path-expected.txt deleted file mode 100644 index 44f3c1e..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-gradient-without-path-expected.txt +++ /dev/null
@@ -1,15 +0,0 @@ -Series of tests to ensure that no gradient is drawn without path - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS imgdata[4] is 0 -PASS imgdata[5] is 128 -PASS imgdata[6] is 0 -PASS imgdata[4] is 0 -PASS imgdata[5] is 128 -PASS imgdata[6] is 0 -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-gradient-without-path.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-gradient-without-path.html index a618edb..7e4dc40 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-gradient-without-path.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-gradient-without-path.html
@@ -1,9 +1,38 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <body> -<script src="script-tests/canvas-gradient-without-path.js"></script> +<script> +test(function(t) { + var ctx = document.createElement('canvas').getContext('2d'); + + ctx.fillStyle = 'green'; + ctx.fillRect(0, 0, 100, 100); + + var gradient = ctx.createLinearGradient(0, 0, 0, 100); + gradient.addColorStop(1, 'red'); + ctx.fillStyle = gradient; + + ctx.fill(); + + var imageData = ctx.getImageData(1, 1, 98, 98); + var imgdata = imageData.data; + assert_equals(imgdata[4], 0); + assert_equals(imgdata[5], 128); + assert_equals(imgdata[6], 0); + + ctx.strokeStyle = 'green'; + ctx.lineWidth = 100; + ctx.strokeRect(50, 0, 100, 100); + + ctx.strokeStyle = gradient; + + ctx.stroke(); + + imageData = ctx.getImageData(1, 1, 98, 98); + imgdata = imageData.data; + assert_equals(imgdata[4], 0); + assert_equals(imgdata[5], 128); + assert_equals(imgdata[6], 0); +}, "Series of tests to ensure that no gradient is drawn without path"); +</script> </body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-frameless-document-text.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-frameless-document-text.js deleted file mode 100644 index e28892f9..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-frameless-document-text.js +++ /dev/null
@@ -1,20 +0,0 @@ -description("This verifies that the browser does not crash when drawing text to a canvas in a frame-less document."); - -// It is not clear from the spec whether this is supposed to work and how. -// Therefore, we do not validate the rendering results. We just make sure -// this does not crash the browser. -var canvas1 = document.createElement('canvas'); -var ctx1 = canvas1.getContext('2d'); -var htmlDoc = document.implementation.createHTMLDocument('', '', null); -htmlDoc.adoptNode(canvas1); -var canvas2 = htmlDoc.createElement('canvas'); -var ctx2 = canvas2.getContext('2d'); - -ctx1.font = 'italic 30px Arial'; -ctx2.font = 'italic 30px Arial'; -ctx1.fillText('Text1', 0, 30); -ctx2.fillText('Text1', 0, 30); -ctx1.strokeText('Text2', 0, 60); -ctx2.strokeText('Text2', 0, 60); -ctx1.measureText('Text3'); -ctx2.measureText('Text3'); \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-getContext-invalid.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-getContext-invalid.js deleted file mode 100644 index dec1267..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-getContext-invalid.js +++ /dev/null
@@ -1,13 +0,0 @@ -description("Test that invalid canvas getContext() requests return null."); - -canvas = document.createElement('canvas'); - -shouldBe("canvas.getContext('')", "null"); -shouldBe("canvas.getContext('2d#')", "null"); -shouldBe("canvas.getContext('This is clearly not a valid context name.')", "null"); -shouldBe("canvas.getContext('2d\0')", "null"); -shouldBe("canvas.getContext('2\uFF44')", "null"); -shouldBe("canvas.getContext('2D')", "null"); -shouldThrow("canvas.getContext()"); -shouldBe("canvas.getContext('null')", "null"); -shouldBe("canvas.getContext('undefined')", "null");
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-getImageData-invalid.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-getImageData-invalid.js deleted file mode 100644 index f29db675..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-getImageData-invalid.js +++ /dev/null
@@ -1,18 +0,0 @@ -description("Test the handling of invalid arguments in canvas getImageData()."); - -ctx = document.createElement('canvas').getContext('2d'); - -shouldThrow("ctx.getImageData(NaN, 10, 10, 10)"); -shouldThrow("ctx.getImageData(10, NaN, 10, 10)"); -shouldThrow("ctx.getImageData(10, 10, NaN, 10)"); -shouldThrow("ctx.getImageData(10, 10, 10, NaN)"); -shouldThrow("ctx.getImageData(Infinity, 10, 10, 10)"); -shouldThrow("ctx.getImageData(10, Infinity, 10, 10)"); -shouldThrow("ctx.getImageData(10, 10, Infinity, 10)"); -shouldThrow("ctx.getImageData(10, 10, 10, Infinity)"); -shouldThrow("ctx.getImageData(undefined, 10, 10, 10)"); -shouldThrow("ctx.getImageData(10, undefined, 10, 10)"); -shouldThrow("ctx.getImageData(10, 10, undefined, 10)"); -shouldThrow("ctx.getImageData(10, 10, 10, undefined)"); -shouldThrow("ctx.getImageData(10, 10, 0, 10)"); -shouldThrow("ctx.getImageData(10, 10, 10, 0)");
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-getImageData-negative-source.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-getImageData-negative-source.js deleted file mode 100644 index b6c201c..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-getImageData-negative-source.js +++ /dev/null
@@ -1,29 +0,0 @@ -description("Test the handling of negative sourceRect offset in getImageData()."); - -ctx = document.createElement('canvas').getContext('2d'); - -ctx.fillStyle = 'red'; -ctx.fillRect(0, 0, 100, 100); -ctx.fillStyle = 'green'; -ctx.fillRect(0, 0, 6, 6); - -var imageData = ctx.getImageData(-10, 0, 100, 1); -var imgdata = imageData.data; - -// Fully transparent black -shouldBe("imgdata[0]", "0"); -shouldBe("imgdata[1]", "0"); -shouldBe("imgdata[2]", "0"); -shouldBe("imgdata[3]", "0"); - -// Green -shouldBe("imgdata[60]", "0"); -shouldBe("imgdata[61]", "128"); -shouldBe("imgdata[62]", "0"); -shouldBe("imgdata[63]", "255"); - -// Red -shouldBe("imgdata[64]", "255"); -shouldBe("imgdata[65]", "0"); -shouldBe("imgdata[66]", "0"); -shouldBe("imgdata[67]", "255");
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-gradient-without-path.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-gradient-without-path.js deleted file mode 100644 index 812199e..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-gradient-without-path.js +++ /dev/null
@@ -1,31 +0,0 @@ -description("Series of tests to ensure that no gradient is drawn without path"); -var ctx = document.createElement('canvas').getContext('2d'); - -ctx.fillStyle = 'green'; -ctx.fillRect(0, 0, 100, 100); - -var gradient = ctx.createLinearGradient(0, 0, 0, 100); -gradient.addColorStop(1, 'red'); -ctx.fillStyle = gradient; - -ctx.fill(); - -var imageData = ctx.getImageData(1, 1, 98, 98); -var imgdata = imageData.data; -shouldBe("imgdata[4]", "0"); -shouldBe("imgdata[5]", "128"); -shouldBe("imgdata[6]", "0"); - -ctx.strokeStyle = 'green'; -ctx.lineWidth = 100; -ctx.strokeRect(50, 0, 100, 100); - -ctx.strokeStyle = gradient; - -ctx.stroke(); - -imageData = ctx.getImageData(1, 1, 98, 98); -imgdata = imageData.data; -shouldBe("imgdata[4]", "0"); -shouldBe("imgdata[5]", "128"); -shouldBe("imgdata[6]", "0");
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-auto-repeat-huge-grid.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-auto-repeat-huge-grid.html index 6aa75a5..1ba7d88b 100644 --- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-auto-repeat-huge-grid.html +++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-auto-repeat-huge-grid.html
@@ -11,6 +11,12 @@ .wideGrid { width: 1000000000px; } .tallGrid { height: 1000000000px; } +.width25k { width: 25000px; } +.height25k { height: 25000px; } + +.lastColumn { grid-column: -2 / -1; } +.lastRow { grid-row: -2 / -1; } + .minSizeWideGrid { min-width: 1000000000px; } .minSizeTallGrid { min-height: 1000000000px; } @@ -20,130 +26,454 @@ .lotsOfAutoRepeatWithAutoFitCols { grid-template-columns: repeat(auto-fit, 10px 2px 8px) repeat(10, 1px); } .lotsOfAutoRepeatWithAutoFillCols { grid-template-columns: repeat(auto-fill, 10px 2px 8px 7px 20px) repeat(10, 1px); } +.lotsOfFixedRepeatWithAutoFitColsReversed { grid-template-columns: repeat(992, 1px) repeat(auto-fit, 10px 2px 8px); } +.lotsOfFixedRepeatWithAutoFillColsReversed { grid-template-columns: repeat(995, 1px) repeat(auto-fill, 10px 2px 8px 7px 20px); } + .lotsOfFixedRepeatWithAutoFitRows { grid-template-rows: repeat(auto-fit, 10px 2px 8px) repeat(992, 1px); } .lotsOfFixedRepeatWithAutoFillRows { grid-template-rows: repeat(auto-fill, 10px 2px 8px 7px 20px) repeat(995, 1px); } .lotsOfAutoRepeatWithAutoFitRows { grid-template-rows: repeat(auto-fit, 10px 2px 8px) repeat(10, 1px); } .lotsOfAutoRepeatWithAutoFillRows { grid-template-rows: repeat(auto-fill, 10px 2px 8px 7px 20px) repeat(10, 1px); } + +.lotsOfFixedRepeatWithAutoFitRowsReversed { grid-template-rows: repeat(992, 1px) repeat(auto-fit, 10px 2px 8px); } +.lotsOfFixedRepeatWithAutoFillRowsReversed { grid-template-rows: repeat(995, 1px) repeat(auto-fill, 10px 2px 8px 7px 20px); } + +.autoFitRows25px { grid-template-rows: repeat(auto-fit, 10px 2px 8px 5px); } +.autoFitCols25px { grid-template-columns: repeat(auto-fit, 10px 2px 8px 5px); } + +.autoFillRows25px { grid-template-rows: repeat(auto-fill, 17px 8px); } +.autoFillCols25px { grid-template-columns: repeat(auto-fill, 2px 23px); } + +.autoFitRows205pxFixed5px { grid-template-rows: repeat(900, 5px) repeat(auto-fit, 20px 50px 13px 50px 72px); } +.autoFitCols205pxFixed5px { grid-template-columns: repeat(900, 5px) repeat(auto-fit, 20px 50px 13px 50px 72px); } + +.autoFillRows205pxFixed5px { grid-template-rows: repeat(900, 5px) repeat(auto-fill, 200px 5px); } +.autoFillCols205pxFixed5px { grid-template-columns: repeat(900, 5px) repeat(auto-fill, 200px 5px); } + +.autoFitAndAThousandFixedRows { grid-template-rows: repeat(auto-fit, 20px 50px 72px) repeat(1000, 37px); } +.autoFitAndAThousandFixedCols { grid-template-columns: repeat(auto-fit, 20px 50px 72px) repeat(1000, 37px); } + +.autoFillAndAThousandFixedRows { grid-template-rows: repeat(auto-fill, 2px) repeat(1000, 37px); } +.autoFillAndAThousandFixedCols { grid-template-columns: repeat(auto-fill, 2px) repeat(1000, 37px); } + +.autoFitAndMoreThanThousandFixedRows { grid-template-rows: repeat(700, 7px) repeat(auto-fit, 11px 13px 125px) repeat(600, 6px); } +.autoFitAndMoreThanThousandFixedCols { grid-template-columns: repeat(700, 7px) repeat(auto-fit, 11px 13px 125px) repeat(600, 6px); } + +.autoFillAndMoreThanThousandFixedRows { grid-template-rows: repeat(700, 7px) repeat(auto-fill, 20px 50px 72px) repeat(600, 6px); } +.autoFillAndMoreThanThousandFixedCols { grid-template-columns: repeat(700, 7px) repeat(auto-fill, 20px 50px 72px) repeat(600, 6px); } + +.handMadeMoreThanThousandAutoFillRows { grid-template-rows: repeat(auto-fill, 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 999px); } +.handMadeMoreThanThousandAutoFillCols { grid-template-columns: repeat(auto-fill, 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 999px); } + +.handMadeMoreThanThousandAutoFitRows { grid-template-rows: repeat(auto-fit, 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 999px); } +.handMadeMoreThanThousandAutoFitCols { grid-template-columns: repeat(auto-fit, 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 10px 2px 13px 1px 3px 8px 7px 2px 12px 5px 999px); } + </style> <div id="wideAutoFillGrid" class="grid wideGrid lotsOfFixedRepeatWithAutoFillCols"></div> <div id="wideAutoFitGrid" class="grid wideGrid lotsOfFixedRepeatWithAutoFitCols"> <div>Item1</div> <div>Item2</div> - <div>Item3</div> + <div class="lastColumn">Item3</div> </div> -<div id="tallAutoFillGrid" class="grid tallGrid lotsOfFixedRepeatWithAutoFillRows"></div> -<div id="tallAutoFitGrid" class="grid tallGrid lotsOfFixedRepeatWithAutoFitRows"> +<div id="autoFillGrid" class="grid tallGrid lotsOfFixedRepeatWithAutoFillRows"></div> +<div id="autoFitGrid" class="grid tallGrid lotsOfFixedRepeatWithAutoFitRows"> <div>Item1</div> <div>Item2</div> - <div>Item3</div> + <div class="lastRow">Item3</div> </div> <div id="wideAutoFillGridFewRepetitions" class="grid wideGrid lotsOfAutoRepeatWithAutoFillCols"></div> <div id="wideAutoFitGridFewRepetitions" class="grid wideGrid lotsOfAutoRepeatWithAutoFitCols"> <div>Item1</div> <div>Item2</div> - <div>Item3</div> + <div class="lastColumn">Item3</div> </div> <div id="tallAutoFillGridFewRepetitions" class="grid tallGrid lotsOfAutoRepeatWithAutoFillRows"></div> <div id="tallAutoFitGridFewRepetitions" class="grid tallGrid lotsOfAutoRepeatWithAutoFitRows"> <div>Item1</div> <div>Item2</div> - <div>Item3</div> + <div class="lastRow">Item3</div> +</div> + +<div id="wideAutoFillGridReversed" class="grid wideGrid lotsOfFixedRepeatWithAutoFillColsReversed"></div> +<div id="wideAutoFitGridReversed" class="grid wideGrid lotsOfFixedRepeatWithAutoFitColsReversed"> + <div>Item1</div> + <div>Item2</div> + <div class="lastColumn">Item3</div> +</div> + +<div id="tallAutoFillGridReversed" class="grid tallGrid lotsOfFixedRepeatWithAutoFillRowsReversed"></div> +<div id="tallAutoFitGridReversed" class="grid tallGrid lotsOfFixedRepeatWithAutoFitRowsReversed"> + <div>Item1</div> + <div>Item2</div> + <div class="lastRow">Item3</div> </div> <div id="wideAutoFillGridFewRepetitionsMinSize" class="grid lotsOfAutoRepeatWithAutoFillCols minSizeWideGrid min-content"></div> <div id="wideAutoFitGridFewRepetitionsMinSize" class="grid lotsOfAutoRepeatWithAutoFitCols minSizeWideGrid min-content"> <div>Item1</div> <div>Item2</div> - <div>Item3</div> + <div class="lastColumn">Item3</div> </div> <div id="tallAutoFillGridFewRepetitionsMinSize" class="grid lotsOfAutoRepeatWithAutoFillRows minSizeTallGrid min-content"></div> <div id="tallAutoFitGridFewRepetitionsMinSize" class="grid lotsOfAutoRepeatWithAutoFitRows minSizeTallGrid min-content"> <div>Item1</div> <div>Item2</div> - <div>Item3</div> + <div class="lastRow">Item3</div> +</div> + +<div id="aThousandAutoFillRows" class="grid height25k autoFillRows25px"></div> +<div id="aThousandAutoFitRows" class="grid height25k autoFitRows25px"> + <div>Item1</div> + <div>Item2</div> + <div class="lastRow">Item3</div> +</div> + +<div id="aThousandAutoFillCols" class="grid width25k autoFillCols25px"></div> +<div id="aThousandAutoFitCols" class="grid width25k autoFitCols25px"> + <div>Item1</div> + <div>Item2</div> + <div class="lastColumn">Item3</div> +</div> + +<div id="aThousandAutoFillAndFixedRows" class="grid height25k autoFillRows205pxFixed5px"></div> +<div id="aThousandAutoFitAndFixedRows" class="grid height25k autoFitRows205pxFixed5px"> + <div>Item1</div> + <div>Item2</div> + <div class="lastRow">Item3</div> +</div> + +<div id="aThousandAutoFillAndFixedCols" class="grid width25k autoFillCols205pxFixed5px"></div> +<div id="aThousandAutoFitAndFixedCols" class="grid width25k autoFitCols205pxFixed5px"> + <div>Item1</div> + <div>Item2</div> + <div class="lastColumn">Item3</div> +</div> + +<div id="aThousandFixedZeroAutoFillRows" class="grid height25k autoFillAndAThousandFixedRows"></div> +<div id="aThousandFixedZeroAutoFitRows" class="grid height25k autoFitAndAThousandFixedRows"> + <div>Item1</div> + <div>Item2</div> + <div class="lastRow">Item3</div> +</div> + +<div id="aThousandFixedZeroAutoFillCols" class="grid width25k autoFillAndAThousandFixedCols"></div> +<div id="aThousandFixedZeroAutoFitCols" class="grid width25k autoFitAndAThousandFixedCols"> + <div>Item1</div> + <div>Item2</div> + <div class="lastColumn">Item3</div> +</div> + + +<div id="aThousandFixedZeroAutoFillRowsFreeSpace" class="grid tallGrid autoFillAndAThousandFixedRows"></div> +<div id="aThousandFixedZeroAutoFitRowsFreeSpace" class="grid tallGrid autoFitAndAThousandFixedRows"> + <div>Item1</div> + <div>Item2</div> + <div class="lastRow">Item3</div> +</div> + +<div id="aThousandFixedZeroAutoFillColsFreeSpace" class="grid wideGrid autoFillAndAThousandFixedCols"></div> +<div id="aThousandFixedZeroAutoFitColsFreeSpace" class="grid wideGrid autoFitAndAThousandFixedCols"> + <div>Item1</div> + <div>Item2</div> + <div class="lastColumn">Item3</div> +</div> + +<div id="moreThanAThousandFixedZeroAutoFillRows" class="grid height25k autoFillAndMoreThanThousandFixedRows"></div> +<div id="moreThanAThousandFixedZeroAutoFitRows" class="grid height25k autoFitAndMoreThanThousandFixedRows"> + <div>Item1</div> + <div>Item2</div> + <div class="lastRow">Item3</div> +</div> + +<div id="moreThanAThousandFixedZeroAutoFillCols" class="grid width25k autoFillAndMoreThanThousandFixedCols"></div> +<div id="moreThanAThousandFixedZeroAutoFitCols" class="grid width25k autoFitAndMoreThanThousandFixedCols"> + <div>Item1</div> + <div>Item2</div> + <div class="lastColumn">Item3</div> +</div> + +<div id="handMadeAutoFillRows" class="grid tallGrid handMadeMoreThanThousandAutoFillRows"></div> +<div id="handMadeAutoFitRows" class="grid tallGrid handMadeMoreThanThousandAutoFitRows"> + <div>Item1</div> + <div>Item2</div> + <div class="lastRow">Item3</div> +</div> + +<div id="handMadeAutoFillCols" class="grid wideGrid handMadeMoreThanThousandAutoFillCols"></div> +<div id="handMadeAutoFitCols" class="grid wideGrid handMadeMoreThanThousandAutoFitCols"> + <div>Item1</div> + <div>Item2</div> + <div class="lastColumn">Item3</div> </div> <script> function testElement(element, property, length) { - var tracks = getComputedStyle(document.getElementById(element), '').getPropertyValue(property).split(' '); + var propertyValue = getComputedStyle(document.getElementById(element), '').getPropertyValue(property); + + if (propertyValue == "") { + assert_equals(length, 0); + return []; + } + + var tracks = propertyValue.split(' '); assert_equals(tracks.length, length); return tracks; } test(function() { - testElement("wideAutoFillGrid", "grid-template-columns", 1000); - testElement("wideAutoFitGrid", "grid-template-columns", 998); -}, "Test that we don't get more than kGridMaxTracks repetitions even on very wide grids."); + var autoFillGrid = testElement("wideAutoFillGrid", "grid-template-columns", 1000); + var autoFitGrid = testElement("wideAutoFitGrid", "grid-template-columns", 1000); + + assert_equals(autoFitGrid[1000 - 1], "10px"); + assert_equals(autoFitGrid[1000 - 2], "0px"); + assert_equals(autoFitGrid[0], "10px"); + assert_equals(autoFitGrid[1], "2px"); + + assert_equals(autoFillGrid[1000 - 1], "20px"); + assert_equals(autoFillGrid[1000 - 2], "7px"); + assert_equals(autoFillGrid[0], "10px"); + assert_equals(autoFillGrid[1], "2px"); +}, "Test that we don't get more than kGridMaxTracks repetitions even on very wide grids (normal tracks clamped)."); test(function() { - testElement("tallAutoFillGrid", "grid-template-rows", 1000); - testElement("tallAutoFitGrid", "grid-template-rows", 998); -}, "Test that we don't get more than kGridMaxTracks repetitions even on very tall grids."); + var autoFillGrid = testElement("autoFillGrid", "grid-template-rows", 1000); + var autoFitGrid = testElement("autoFitGrid", "grid-template-rows", 1000); + + assert_equals(autoFitGrid[1000 - 1], "10px"); + assert_equals(autoFitGrid[1000 - 2], "0px"); + assert_equals(autoFitGrid[0], "10px"); + assert_equals(autoFitGrid[1], "2px"); + + assert_equals(autoFillGrid[1000 - 1], "20px"); + assert_equals(autoFillGrid[1000 - 2], "7px"); + assert_equals(autoFillGrid[0], "10px"); + assert_equals(autoFillGrid[1], "2px"); +}, "Test that we don't get more than kGridMaxTracks repetitions even on very tall grids (normal tracks clamped)."); test(function() { - var wideAutoFillGrid = document.getElementById("wideAutoFillGridFewRepetitions"); - var wideAutoFitGrid = document.getElementById("wideAutoFitGridFewRepetitions"); + var autoFillGrid = testElement("wideAutoFillGridReversed", "grid-template-columns", 1000); + var autoFitGrid = testElement("wideAutoFitGridReversed", "grid-template-columns", 1000); - wideAutoFillGrid.style.gridGap = "100px"; - wideAutoFitGrid.style.gridGap = "100px"; + assert_equals(autoFitGrid[1000 - 1], "2px"); + assert_equals(autoFitGrid[1000 - 2], "0px"); + assert_equals(autoFitGrid[0], "1px"); + assert_equals(autoFitGrid[1], "1px"); - testElement("wideAutoFillGridFewRepetitions", "grid-template-columns", 1000); - testElement("wideAutoFitGridFewRepetitions", "grid-template-columns", 1000); + assert_equals(autoFillGrid[1000 - 1], "20px"); + assert_equals(autoFillGrid[1000 - 2], "7px"); + assert_equals(autoFillGrid[0], "1px"); + assert_equals(autoFillGrid[1], "1px"); +}, "Test that we don't get more than kGridMaxTracks repetitions even on very wide grids (auto repeat tracks clamped)."); - wideAutoFillGrid.style.gridGap = "1000000px"; - wideAutoFitGrid.style.gridGap = "1000000px"; +test(function() { + var autoFillGrid = testElement("tallAutoFillGridReversed", "grid-template-rows", 1000); + var autoFitGrid = testElement("tallAutoFitGridReversed", "grid-template-rows", 1000); + + assert_equals(autoFitGrid[1000 - 1], "2px"); + assert_equals(autoFitGrid[1000 - 2], "0px"); + assert_equals(autoFitGrid[0], "1px"); + assert_equals(autoFitGrid[1], "1px"); + + assert_equals(autoFillGrid[1000 - 1], "20px"); + assert_equals(autoFillGrid[1000 - 2], "7px"); + assert_equals(autoFillGrid[0], "1px"); + assert_equals(autoFillGrid[1], "1px"); +}, "Test that we don't get more than kGridMaxTracks repetitions even on very tall grids (auto repeat tracks clamped)."); + +test(function() { + var fillGridElement = document.getElementById("wideAutoFillGridFewRepetitions"); + var fitGridElement = document.getElementById("wideAutoFitGridFewRepetitions"); + + fillGridElement.style.gridGap = "100px"; + fitGridElement.style.gridGap = "100px"; + + var autoFillGrid = testElement("wideAutoFillGridFewRepetitions", "grid-template-columns", 1000); + var autoFitGrid = testElement("wideAutoFitGridFewRepetitions", "grid-template-columns", 1000); + + assert_equals(autoFitGrid[1000 - 1], "10px"); + assert_equals(autoFitGrid[1000 - 2], "0px"); + assert_equals(autoFillGrid[1000 - 1], "20px"); + assert_equals(autoFillGrid[1000 - 2], "7px"); + + fillGridElement.style.gridGap = "1000000px"; + fitGridElement.style.gridGap = "1000000px"; testElement("wideAutoFillGridFewRepetitions", "grid-template-columns", 130); testElement("wideAutoFitGridFewRepetitions", "grid-template-columns", 82); - wideAutoFillGrid.style.gridGap = "0px"; - wideAutoFitGrid.style.gridGap = "0px"; + fillGridElement.style.gridGap = "0px"; + fitGridElement.style.gridGap = "0px"; }, "Test that we don't get more than kGridMaxTracks repetitions even on very wide grids with gaps."); test(function() { - var tallAutoFillGrid = document.getElementById("tallAutoFillGridFewRepetitions"); - var tallAutoFitGrid = document.getElementById("tallAutoFitGridFewRepetitions"); + var autoFillGridElement = document.getElementById("tallAutoFillGridFewRepetitions"); + var autoFitGridElement = document.getElementById("tallAutoFitGridFewRepetitions"); - tallAutoFillGrid.style.gridGap = "100px"; - tallAutoFitGrid.style.gridGap = "100px"; + autoFillGridElement.style.gridGap = "100px"; + autoFitGridElement.style.gridGap = "100px"; - testElement("tallAutoFillGridFewRepetitions", "grid-template-rows", 1000); - testElement("tallAutoFitGridFewRepetitions", "grid-template-rows", 1000); + var autoFillGrid = testElement("tallAutoFillGridFewRepetitions", "grid-template-rows", 1000); + var autoFitGrid = testElement("tallAutoFitGridFewRepetitions", "grid-template-rows", 1000); - tallAutoFillGrid.style.gridGap = "1000000px"; - tallAutoFitGrid.style.gridGap = "1000000px"; + assert_equals(autoFitGrid[1000 - 1], "10px"); + assert_equals(autoFitGrid[1000 - 2], "0px"); + assert_equals(autoFillGrid[1000 - 1], "20px"); + assert_equals(autoFillGrid[1000 - 2], "7px"); + + autoFillGridElement.style.gridGap = "1000000px"; + autoFitGridElement.style.gridGap = "1000000px"; testElement("tallAutoFillGridFewRepetitions", "grid-template-rows", 130); testElement("tallAutoFitGridFewRepetitions", "grid-template-rows", 82); - tallAutoFillGrid.style.gridGap = "0px"; - tallAutoFitGrid.style.gridGap = "0px"; + autoFillGridElement.style.gridGap = "0px"; + autoFitGridElement.style.gridGap = "0px"; }, "Test that we don't get more than kGridMaxTracks repetitions even on very tall grids with gaps."); - test(function() { +test(function() { var autoFillCols = testElement("wideAutoFillGridFewRepetitionsMinSize", "grid-template-columns", 1000); var autoFitCols = testElement("wideAutoFitGridFewRepetitionsMinSize", "grid-template-columns", 1000); /* Check that clamping auto repetitions does not reduce the amount of the other tracks. */ - assert_equals(autoFillCols[1000 - 10 - 1], "20px"); - assert_equals(autoFillCols[1000 - 10], "1px"); - assert_equals(autoFitCols[1000 - 10 - 1], "0px"); - assert_equals(autoFitCols[1000 - 10], "1px"); + assert_equals(autoFillCols[1000 - 1], "20px"); + assert_equals(autoFillCols[1000 - 2], "7px"); + assert_equals(autoFitCols[1000 - 1], "10px"); + assert_equals(autoFitCols[1000 - 2], "0px"); +}, "Test that we don't get more than kGridMaxTracks repetitions even on very wide grids with gaps and min-width."); +test(function() { var autoFillRows = testElement("tallAutoFillGridFewRepetitionsMinSize", "grid-template-rows", 1000); var autoFitRows = testElement("tallAutoFitGridFewRepetitionsMinSize", "grid-template-rows", 1000); - /* Check that clamping auto repetitions does not reduce the amount of the other tracks. */ - assert_equals(autoFillRows[1000 - 10 - 1], "20px"); - assert_equals(autoFillRows[1000 - 10], "1px"); - assert_equals(autoFitRows[1000 - 10 - 1], "0px"); - assert_equals(autoFitRows[1000 - 10], "1px"); - }, "Test that we don't get more than kGridMaxTracks repetitions even on very wide grids with gaps and min-width."); + assert_equals(autoFillRows[1000 - 1], "20px"); + assert_equals(autoFillRows[1000 - 2], "7px"); + assert_equals(autoFitRows[1000 - 1], "10px"); + assert_equals(autoFitRows[1000 - 2], "0px"); +}, "Test that we don't get more than kGridMaxTracks repetitions even on very tall grids with gaps and min-height."); + +test(function() { + var autoFillRows = testElement("aThousandAutoFillRows", "grid-template-rows", 1000); + var autoFitRows = testElement("aThousandAutoFitRows", "grid-template-rows", 1000); + + assert_equals(autoFillRows[1000 - 1], "8px"); + assert_equals(autoFillRows[1000 - 2], "17px"); + assert_equals(autoFitRows[1000 - 1], "5px"); + assert_equals(autoFitRows[1000 - 2], "0px"); +}, "Test that we don't crash when there are exactly kGridMaxTracks auto repeat rows on very tall grids."); + +test(function() { + var autoFillCols = testElement("aThousandAutoFillCols", "grid-template-columns", 1000); + var autoFitCols = testElement("aThousandAutoFitCols", "grid-template-columns", 1000); + + assert_equals(autoFillCols[1000 - 1], "23px"); + assert_equals(autoFillCols[1000 - 2], "2px"); + assert_equals(autoFitCols[1000 - 1], "5px"); + assert_equals(autoFitCols[1000 - 2], "0px"); +}, "Test that we don't crash when there are exactly kGridMaxTracks auto repeat columns on very wide grids."); + +test(function() { + var autoFillRows = testElement("aThousandAutoFillAndFixedRows", "grid-template-rows", 1000); + var autoFitRows = testElement("aThousandAutoFitAndFixedRows", "grid-template-rows", 1000); + + assert_equals(autoFillRows[1000 - 1], "5px"); + assert_equals(autoFillRows[1000 - 2], "200px"); + assert_equals(autoFitRows[1000 - 1], "72px"); + assert_equals(autoFitRows[1000 - 2], "0px"); +}, "Test that we don't crash when there are exactly kGridMaxTracks (normal and auto-repeat) rows on very tall grids."); + +test(function() { + var autoFillCols = testElement("aThousandAutoFillAndFixedCols", "grid-template-columns", 1000); + var autoFitCols = testElement("aThousandAutoFitAndFixedCols", "grid-template-columns", 1000); + + assert_equals(autoFillCols[1000 - 1], "5px"); + assert_equals(autoFillCols[1000 - 2], "200px"); + assert_equals(autoFitCols[1000 - 1], "72px"); + assert_equals(autoFitCols[1000 - 2], "0px"); +}, "Test that we don't crash when there are exactly kGridMaxTracks (normal and auto-repeat) columns on very wide grids."); + +test(function() { + var autoFillGrid = testElement("aThousandFixedZeroAutoFillRows", "grid-template-rows", 1000); + var autoFitGrid = testElement("aThousandFixedZeroAutoFitRows", "grid-template-rows", 1000); + + assert_equals(autoFillGrid[1000 - 1], "37px"); + assert_equals(autoFillGrid[0], "2px"); + assert_equals(autoFitGrid[1000 - 1], "37px"); + assert_equals(autoFitGrid[0], "20px"); +}, "Test that we don't crash when there are exactly kGridMaxTracks non auto-repeat rows on very tall grids."); + +test(function() { + var autoFillGrid = testElement("aThousandFixedZeroAutoFillCols", "grid-template-columns", 1000); + var autoFitGrid = testElement("aThousandFixedZeroAutoFitCols", "grid-template-columns", 1000); + + assert_equals(autoFillGrid[1000 - 1], "37px"); + assert_equals(autoFillGrid[0], "2px"); + assert_equals(autoFitGrid[1000 - 1], "37px"); + assert_equals(autoFitGrid[0], "20px"); +}, "Test that we don't crash when there are exactly kGridMaxTracks non auto-repeat columns on very wide grids."); + +test(function() { + var autoFillGrid = testElement("aThousandFixedZeroAutoFillRowsFreeSpace", "grid-template-rows", 1000); + var autoFitGrid = testElement("aThousandFixedZeroAutoFitRowsFreeSpace", "grid-template-rows", 1000); + + assert_equals(autoFillGrid[1000 - 1], "2px"); + assert_equals(autoFillGrid[0], "2px"); + assert_equals(autoFitGrid[1000 - 1], "20px"); + assert_equals(autoFitGrid[0], "20px"); +}, "Test that we don't crash when there are exactly kGridMaxTracks non auto-repeat rows on very tall grids with enough room for auto repetitions."); + +test(function() { + var autoFillGrid = testElement("aThousandFixedZeroAutoFillColsFreeSpace", "grid-template-columns", 1000); + var autoFitGrid = testElement("aThousandFixedZeroAutoFitColsFreeSpace", "grid-template-columns", 1000); + + assert_equals(autoFillGrid[1000 - 1], "2px"); + assert_equals(autoFillGrid[0], "2px"); + assert_equals(autoFitGrid[1000 - 1], "20px"); + assert_equals(autoFitGrid[0], "20px"); +}, "Test that we don't crash when there are exactly kGridMaxTracks non auto-repeat columns on very wide grids with enough room for auto repetitions."); + +test(function() { + var autoFillGrid = testElement("moreThanAThousandFixedZeroAutoFillRows", "grid-template-rows", 1000); + var autoFitGrid = testElement("moreThanAThousandFixedZeroAutoFitRows", "grid-template-rows", 1000); + + assert_equals(autoFillGrid[1000 - 1], "72px"); + assert_equals(autoFillGrid[0], "7px"); + assert_equals(autoFitGrid[1000 - 1], "125px"); + assert_equals(autoFitGrid[0], "7px"); +}, "Test that we don't crash when there are more than kGridMaxTracks non auto-repeat rows on very tall grids."); + +test(function() { + var autoFillGrid = testElement("moreThanAThousandFixedZeroAutoFillCols", "grid-template-columns", 1000); + var autoFitGrid = testElement("moreThanAThousandFixedZeroAutoFitCols", "grid-template-columns", 1000); + + assert_equals(autoFillGrid[1000 - 1], "72px"); + assert_equals(autoFillGrid[0], "7px"); + assert_equals(autoFitGrid[1000 - 1], "125px"); + assert_equals(autoFitGrid[0], "7px"); +}, "Test that we don't crash when there are more than kGridMaxTracks non auto-repeat columns on very wide grids."); + +test(function() { + var autoFillGrid = testElement("handMadeAutoFillRows", "grid-template-rows", 1000); + var autoFitGrid = testElement("handMadeAutoFitRows", "grid-template-rows", 1000); + + assert_equals(autoFillGrid[1000 - 1], "5px"); + assert_equals(autoFillGrid[0], "10px"); + assert_equals(autoFitGrid[1000 - 1], "5px"); + assert_equals(autoFitGrid[0], "10px"); +}, "Test that we don't crash when there are more than kGridMaxTracks rows in the auto repeat <track-list>."); + +test(function() { + var autoFillGrid = testElement("handMadeAutoFillCols", "grid-template-columns", 1000); + var autoFitGrid = testElement("handMadeAutoFitCols", "grid-template-columns", 1000); + + assert_equals(autoFillGrid[1000 - 1], "5px"); + assert_equals(autoFillGrid[0], "10px"); + assert_equals(autoFitGrid[1000 - 1], "5px"); + assert_equals(autoFitGrid[0], "10px"); +}, "Test that we don't crash when there are more than kGridMaxTracks columns in the auto repeat <track-list>."); </script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt index fe7d832..e456260a 100644 --- a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt
@@ -236,7 +236,7 @@ r: 0px resize: none right: auto -rotate: 0deg +rotate: none rx: auto ry: auto scale: none
diff --git a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt index f157886..81a1fc42 100644 --- a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt
@@ -236,7 +236,7 @@ r: 0px resize: none right: auto -rotate: 0deg +rotate: none rx: auto ry: auto scale: none
diff --git a/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-break-word-fit-content-expected.html b/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-break-word-fit-content-expected.html new file mode 100644 index 0000000..e398f17 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-break-word-fit-content-expected.html
@@ -0,0 +1,8 @@ +<!DOCTYPE html> +<style> +html { + font-family: Courier, monospace; +} +</style> +<table><tr><td>.<br>.<br>.</td></tr></table> +<p><span>.<br>.<br>.</span></p>
diff --git a/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-break-word-fit-content.html b/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-break-word-fit-content.html new file mode 100644 index 0000000..9e8b51c --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-break-word-fit-content.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<style> +html { + font-family: Courier, monospace; +} +td, span { + word-break: break-word; +} +span { + float: left; +} +table, p { + width: 1ch; +} +</style> +<table><tr><td>...</td></tr></table> +<p><span>...</span></p>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/HTMLElement/set-inner-outer-optimization.html b/third_party/WebKit/LayoutTests/fast/dom/HTMLElement/set-inner-outer-optimization.html index 7016854..3c774041 100644 --- a/third_party/WebKit/LayoutTests/fast/dom/HTMLElement/set-inner-outer-optimization.html +++ b/third_party/WebKit/LayoutTests/fast/dom/HTMLElement/set-inner-outer-optimization.html
@@ -100,7 +100,7 @@ runTest('text', 'innerText', '', 'modified'); runTest('text', 'innerText', 'different text', 'modified, with same first child'); - runTest('text', 'innerText', 'text', 'not modified'); + runTest('text', 'innerText', 'text', 'modified, with same first child'); runTest('<a></a>', 'innerText', '', 'modified'); runTest('<a></a>', 'innerText', 'text', 'modified');
diff --git a/third_party/WebKit/LayoutTests/fast/dom/MutationObserver/observe-exceptions-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/MutationObserver/observe-exceptions-expected.txt index 8a710d6..621b3907 100644 --- a/third_party/WebKit/LayoutTests/fast/dom/MutationObserver/observe-exceptions-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/dom/MutationObserver/observe-exceptions-expected.txt
@@ -3,10 +3,10 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". -PASS observer.observe() threw exception TypeError: Failed to execute 'observe' on 'MutationObserver': 2 arguments required, but only 0 present.. -PASS observer.observe(null) threw exception TypeError: Failed to execute 'observe' on 'MutationObserver': 2 arguments required, but only 1 present.. -PASS observer.observe(undefined) threw exception TypeError: Failed to execute 'observe' on 'MutationObserver': 2 arguments required, but only 1 present.. -PASS observer.observe(document.body) threw exception TypeError: Failed to execute 'observe' on 'MutationObserver': 2 arguments required, but only 1 present.. +PASS observer.observe() threw exception TypeError: Failed to execute 'observe' on 'MutationObserver': 1 argument required, but only 0 present.. +PASS observer.observe(null) threw exception TypeError: Failed to execute 'observe' on 'MutationObserver': parameter 1 is not of type 'Node'.. +PASS observer.observe(undefined) threw exception TypeError: Failed to execute 'observe' on 'MutationObserver': parameter 1 is not of type 'Node'.. +PASS observer.observe(document.body) threw exception TypeError: Failed to execute 'observe' on 'MutationObserver': The options object must set at least one of 'attributes', 'characterData', or 'childList' to true.. PASS observer.observe(document.body, null) threw exception TypeError: Failed to execute 'observe' on 'MutationObserver': The options object must set at least one of 'attributes', 'characterData', or 'childList' to true.. PASS observer.observe(document.body, undefined) threw exception TypeError: Failed to execute 'observe' on 'MutationObserver': The options object must set at least one of 'attributes', 'characterData', or 'childList' to true.. PASS observer.observe(null, {attributes: true}) threw exception TypeError: Failed to execute 'observe' on 'MutationObserver': parameter 1 is not of type 'Node'..
diff --git a/third_party/WebKit/LayoutTests/fast/domurl/url-search.html b/third_party/WebKit/LayoutTests/fast/domurl/url-search.html index 41d471d2..66953599 100644 --- a/third_party/WebKit/LayoutTests/fast/domurl/url-search.html +++ b/third_party/WebKit/LayoutTests/fast/domurl/url-search.html
@@ -27,6 +27,9 @@ url.search = '?b'; assert_equals(url.search, '?b'); + url.search = '??b'; + assert_equals(url.search, '??b'); + url.search = 'a#b'; assert_equals(url.search, '?a%23b');
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/multi-pointer-event-in-slop-region.html b/third_party/WebKit/LayoutTests/fast/events/pointerevents/multi-pointer-event-in-slop-region.html new file mode 100644 index 0000000..bf2d937 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/multi-pointer-event-in-slop-region.html
@@ -0,0 +1,74 @@ +<!DOCTYPE html> +<script src='../../../resources/testharness.js'></script> +<script src='../../../resources/testharnessreport.js'></script> +<style type="text/css"> +#box { + width: 600px; + height: 600px; + touch-action: none; +} +</style> +<div id="box" ></div> + +<script type="text/javascript"> + +var touchMoveCount = 0; +var pointerMoveCount = 0; +var box = document.getElementById("box"); +var targetRect = box.getBoundingClientRect(); +var offset = 50; +var x = targetRect.left + offset; +var y = targetRect.top + offset; + +function validTouchMoveResult(event) { + touchMoveCount++; + testTouchMove.step(function () { + assert_equals(event.target.id, "box"); + }); +} + +function validPointerMoveResult(event) { + pointerMoveCount++; + testTouchMove.step(function () { + assert_equals(event.target.id, "box"); + assert_equals(event.pointerType, "touch"); + }); +} + +function callbackValidMoveCount() { + testTouchMove.step(function () { + assert_equals(touchMoveCount, 2); + assert_equals(pointerMoveCount, 3); + }); + testTouchMove.done(); +} + +function testMultiPointerMoveSuppressionInSlopRegion() { + if (window.chrome && chrome.gpuBenchmarking) { + var pointerActions = + [{source: "touch", + actions: [ + { name: "pointerDown", x: x, y: y }, + { name: "pointerMove", x: x, y: y + 10 }, + { name: "pause" }, + { name: "pause" }, + { name: "pause" }, + { name: "pointerMove", x: x, y: y + 6 }, + { name: "pointerUp" }]}, + {source: "touch", + actions: [ + { name: "pause" }, + { name: "pause" }, + { name: "pointerDown", x: x, y: y }, + { name: "pointerMove", x: x, y: y + 10 }, + { name: "pointerUp"}]}]; + chrome.gpuBenchmarking.pointerActionSequence(pointerActions, callbackValidMoveCount); + } +} + +var testTouchMove = async_test('Tests that TouchMoves are not suppressed if a secondary pointer is present during any movement.'); +box.addEventListener('touchmove', validTouchMoveResult); +box.addEventListener('pointermove', validPointerMoveResult); +testMultiPointerMoveSuppressionInSlopRegion(); + +</script> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-in-slop-region.html b/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-in-slop-region.html new file mode 100644 index 0000000..6306b2c --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-in-slop-region.html
@@ -0,0 +1,68 @@ +<!DOCTYPE html> +<script src='../../../resources/testharness.js'></script> +<script src='../../../resources/testharnessreport.js'></script> +<style type="text/css"> +#box { + width: 600px; + height: 600px; + touch-action: none; +} +</style> +<div id="box" ></div> + +<script type="text/javascript"> + +var touchMoveCount = 0; +var pointerMoveCount = 0; +var box = document.getElementById("box"); +var targetRect = box.getBoundingClientRect(); +var offset = 50; +var x = targetRect.left + offset; +var y = targetRect.top + offset; + +function validTouchMoveResult(event) { + touchMoveCount++; + testTouchMove.step(function () { + assert_equals(event.target.id, "box"); + }); +} + +function validPointerMoveResult(event) { + pointerMoveCount++; + testTouchMove.step(function () { + assert_equals(event.target.id, "box"); + assert_equals(event.pointerType, "touch"); + }); +} + +function callbackValidMoveCount() { + testTouchMove.step(function () { + assert_equals(touchMoveCount, 3); + assert_equals(pointerMoveCount, 5); + }); + testTouchMove.done(); +} + +function testTouchMoveSuppressionInSlopRegion() { + if (window.chrome && chrome.gpuBenchmarking) { + var pointerActions = + [{source: "touch", + actions: [ + { name: "pointerDown", x: x, y: y }, + { name: "pointerMove", x: x, y: y + 10 }, + { name: "pointerMove", x: x, y: y + 20 }, + { name: "pointerMove", x: x, y: y + 10 }, + { name: "pointerUp" }, + { name: "pointerDown", x: x, y: y }, + { name: "pointerMove", x: x, y: y + 10 }, + { name: "pointerMove", x: x, y: y + 20 }]}]; + chrome.gpuBenchmarking.pointerActionSequence(pointerActions, callbackValidMoveCount); + } +} + +var testTouchMove = async_test('Tests that TouchMoves are suppressed if within the slop suppression region.'); +box.addEventListener('touchmove', validTouchMoveResult); +box.addEventListener('pointermove', validPointerMoveResult); +testTouchMoveSuppressionInSlopRegion(); + +</script> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/touch-user-gesture.html b/third_party/WebKit/LayoutTests/fast/events/touch/touch-user-gesture.html index 4a2e751..c3909678 100644 --- a/third_party/WebKit/LayoutTests/fast/events/touch/touch-user-gesture.html +++ b/third_party/WebKit/LayoutTests/fast/events/touch/touch-user-gesture.html
@@ -57,7 +57,7 @@ eventSender.addTouchPoint(targetX, targetY); testPopupOnEventDuring('touchstart', false, function() { eventSender.touchStart(); }); eventSender.updateTouchPoint(0, targetX + 10, targetY); -testPopupOnEventDuring('touchmove', false, function() { eventSender.touchMove("movedBeyondSlopRegion"); }); +testPopupOnEventDuring('touchmove', false, function() { eventSender.touchMove(); }); eventSender.notifyStartOfTouchScroll(); eventSender.releaseTouchPoint(0); testPopupOnEventDuring('touchend', false, function() { eventSender.touchEnd(); });
diff --git a/third_party/WebKit/LayoutTests/fast/files/file-reader-abort-expected.txt b/third_party/WebKit/LayoutTests/fast/files/file-reader-abort-expected.txt index 98d62e7..715fc4f 100644 --- a/third_party/WebKit/LayoutTests/fast/files/file-reader-abort-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/files/file-reader-abort-expected.txt
@@ -1,7 +1,6 @@ Test that FileReader.abort works. Received loadstart event -Received error event: AbortError Received abort event Received loadend event DONE
diff --git a/third_party/WebKit/LayoutTests/fast/text/line-break-8bit-after-16bit-expected.html b/third_party/WebKit/LayoutTests/fast/text/line-break-8bit-after-16bit-expected.html new file mode 100644 index 0000000..a274316 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/line-break-8bit-after-16bit-expected.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<style> +@font-face { + font-family: AhemU; + src: url(../../third_party/adobe-fonts/CSSFWOrientationTest.otf); +} +div { + font-family: Ahem, AhemU; + font-size: 20px; + width: 3ch; +} +</style> +<body> + <div>fo–bar</div> + <div>国国国bar</div> + <div>あああbar</div> + <div>国国、bar</div> +</body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/line-break-8bit-after-16bit.html b/third_party/WebKit/LayoutTests/fast/text/line-break-8bit-after-16bit.html new file mode 100644 index 0000000..78c0d71 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/line-break-8bit-after-16bit.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<style> +@font-face { + font-family: AhemU; + src: url(../../third_party/adobe-fonts/CSSFWOrientationTest.otf); +} +div { + font-family: Ahem, AhemU; + font-size: 20px; + width: 3ch; +} +</style> +<body> + <div><span>fo–</span>bar</div> + <div><span>国国国</span>bar</div> + <div>あああ<span>bar</span></div> + <div><span>国国、</span>bar</div> +</body>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-frame-navigate.html b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-frame-navigate.html index 7cc024d..d3f8bac 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-frame-navigate.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-frame-navigate.html
@@ -11,7 +11,6 @@ { var iframe = document.getElementById("iframe"); iframe.setAttribute("src", "resources/resource-tree-frame-navigate-iframe-after.html"); - document.body.appendChild(iframe); } function test()
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 e2ab479..494994b 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js
@@ -41,7 +41,8 @@ finishTime: "formatAsTypeName", thread: "formatAsTypeName", allottedMilliseconds: "formatAsTypeName", - timedOut: "formatAsTypeName" + timedOut: "formatAsTypeName", + networkTime: "formatAsTypeName", }; InspectorTest.InvalidationFormatters = {
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/cross-frame-mouse-source-capabilities.html b/third_party/WebKit/LayoutTests/http/tests/security/cross-frame-mouse-source-capabilities.html new file mode 100644 index 0000000..2ec26f8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/security/cross-frame-mouse-source-capabilities.html
@@ -0,0 +1,46 @@ +<!doctype html> +<html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +var button = null; + +function clickButton() { + if (!button) + button = document.querySelector("button"); + button.click(); +} + +function handler(event) { + assert_not_equals(event.sourceCapabilities, null); + event.sourceCapabilities.customProperty = 42; +} + +async_test(function(t) { + window.addEventListener('message', function(evt) { + if (evt.data === "start") { + setTimeout(clickButton); + return; + } + + assert_equals(evt.data, undefined); + // Check that |sourceCapabilities| is same within the context + // of the same window. We may want to weaken this further and + // not insist on sameness across dispatched events. + button.onclick = function (event) { + assert_not_equals(event.sourceCapabilities, null); + assert_equals(event.sourceCapabilities.customProperty, 42); + t.done(); + }; + button.click(); + }); + +}, 'Test that event sourceCapabilities object is not shared cross-origin'); +</script> +</head> +<body> +<button onclick="handler(event)"></button> +<iframe src="http://localhost:8000/security/resources/cross-frame-mouse-source-capabilities.html"></iframe> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/resources/cross-frame-mouse-source-capabilities.html b/third_party/WebKit/LayoutTests/http/tests/security/resources/cross-frame-mouse-source-capabilities.html new file mode 100644 index 0000000..c75122b --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/security/resources/cross-frame-mouse-source-capabilities.html
@@ -0,0 +1,16 @@ +<!doctype html> +<script> +function handler(event) { + window.top.postMessage(event.sourceCapabilities.customProperty, "*"); +} + +function runTest() { + document.querySelector("button").click(); +} + +window.onload = function () { + setTimeout(runTest, 1000); + window.top.postMessage("start", "*"); +} +</script> +<button onclick="handler(event)"></button>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/resources/link-header.php b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/resources/link-header.php deleted file mode 100644 index 3e5da8f..0000000 --- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/resources/link-header.php +++ /dev/null
@@ -1,3 +0,0 @@ -<?php - header('Link: ' . $_GET['Link']); -?>
diff --git a/third_party/WebKit/LayoutTests/intersection-observer/disconnect.html b/third_party/WebKit/LayoutTests/intersection-observer/disconnect.html new file mode 100644 index 0000000..0c64a96 --- /dev/null +++ b/third_party/WebKit/LayoutTests/intersection-observer/disconnect.html
@@ -0,0 +1,56 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script src="./resources/intersection-observer-test-utils.js"></script> + +<style> +pre, #log { + position: absolute; + top: 0; + left: 200px; +} +.spacer { + height: 700px; +} +#target { + width: 100px; + height: 100px; + background-color: green; +} +</style> + +<div class="spacer"></div> +<div id="target"></div> +<div class="spacer"></div> + +<script> +var entries = []; +var observer; +var target; + +runTestCycle(function() { + assert_equals(window.innerWidth, 800, "Window must be 800 pixels wide."); + assert_equals(window.innerHeight, 600, "Window must be 600 pixels high."); + + target = document.getElementById("target"); + assert_true(!!target, "target exists"); + observer = new IntersectionObserver(function(changes) { + entries = entries.concat(changes) + }); + observer.observe(target); + entries = entries.concat(observer.takeRecords()); + assert_equals(entries.length, 0, "No initial notifications."); + runTestCycle(step0, "First rAF."); +}, "IntersectionObserver should not deliver pending notifications after disconnect()."); + +function step0() { + runTestCycle(step1, "observer.disconnect()"); + document.scrollingElement.scrollTop = 300; + observer.disconnect(); + assert_equals(entries.length, 1, "Initial notification."); +} + +function step1() { + assert_equals(entries.length, 1, "No new notifications."); +} +</script>
diff --git a/third_party/WebKit/LayoutTests/intersection-observer/display-none.html b/third_party/WebKit/LayoutTests/intersection-observer/display-none.html index 28170f6..7d105bf 100644 --- a/third_party/WebKit/LayoutTests/intersection-observer/display-none.html +++ b/third_party/WebKit/LayoutTests/intersection-observer/display-none.html
@@ -38,17 +38,17 @@ function step0() { runTestCycle(step1, "Not-intersecting notification after setting display:none on target."); - checkLastEntry(entries, 0, [8, 108, 8, 108, 8, 108, 8, 108, 0, 800, 0, 600, target]); + checkLastEntry(entries, 0, [8, 108, 8, 108, 8, 108, 8, 108, 0, 800, 0, 600, true]); target.style.display = "none"; } function step1() { runTestCycle(step2, "Intersecting notification after removing display:none on target."); - checkLastEntry(entries, 1, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, target]); + checkLastEntry(entries, 1, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false]); target.style.display = ""; } function step2() { - checkLastEntry(entries, 2, [8, 108, 8, 108, 8, 108, 8, 108, 0, 800, 0, 600, target]); + checkLastEntry(entries, 2, [8, 108, 8, 108, 8, 108, 8, 108, 0, 800, 0, 600, true]); } </script>
diff --git a/third_party/WebKit/LayoutTests/intersection-observer/edge-inclusive-intersection.html b/third_party/WebKit/LayoutTests/intersection-observer/edge-inclusive-intersection.html index 47d9933..6b175ce 100644 --- a/third_party/WebKit/LayoutTests/intersection-observer/edge-inclusive-intersection.html +++ b/third_party/WebKit/LayoutTests/intersection-observer/edge-inclusive-intersection.html
@@ -45,13 +45,13 @@ function step0() { runTestCycle(step1, "Set transform=translateY(200px) on target."); - checkLastEntry(entries, 0, [8, 108, 258, 358, 0, 0, 0, 0, 8, 208, 8, 208, target]); + checkLastEntry(entries, 0, [8, 108, 258, 358, 0, 0, 0, 0, 8, 208, 8, 208, false]); target.style.transform = "translateY(200px)"; } function step1() { runTestCycle(step2, "Set transform=translateY(201px) on target."); - checkLastEntry(entries, 1, [8, 108, 208, 308, 8, 108, 208, 208, 8, 208, 8, 208, target]); + checkLastEntry(entries, 1, [8, 108, 208, 308, 8, 108, 208, 208, 8, 208, 8, 208, true]); target.style.transform = "translateY(201px)"; } @@ -64,6 +64,6 @@ } function step3() { - checkLastEntry(entries, 3, [8, 308, 193, 193, 8, 208, 193, 193, 8, 208, 8, 208, target]); + checkLastEntry(entries, 3, [8, 308, 193, 193, 8, 208, 193, 193, 8, 208, 8, 208, true]); } </script>
diff --git a/third_party/WebKit/LayoutTests/intersection-observer/iframe-no-root.html b/third_party/WebKit/LayoutTests/intersection-observer/iframe-no-root.html index c4cb0e9..5e4f09a 100644 --- a/third_party/WebKit/LayoutTests/intersection-observer/iframe-no-root.html +++ b/third_party/WebKit/LayoutTests/intersection-observer/iframe-no-root.html
@@ -48,7 +48,7 @@ function step0() { document.scrollingElement.scrollTop = 200; runTestCycle(step1, "document.scrollingElement.scrollTop = 200"); - checkLastEntry(entries, 0, [8, 108, 208, 308, 0, 0, 0, 0, 0, 785, 0, 600, target]); + checkLastEntry(entries, 0, [8, 108, 208, 308, 0, 0, 0, 0, 0, 785, 0, 600, false]); } function step1() { @@ -60,11 +60,11 @@ function step2() { document.scrollingElement.scrollTop = 100; runTestCycle(step3, "document.scrollingElement.scrollTop = 100"); - checkLastEntry(entries, 1, [8, 108, -42, 58, 8, 108, 0, 58, 0, 785, 0, 600, target]); + checkLastEntry(entries, 1, [8, 108, -42, 58, 8, 108, 0, 58, 0, 785, 0, 600, true]); } function step3() { - checkLastEntry(entries, 2, [8, 108, -42, 58, 0, 0, 0, 0, 0, 785, 0, 600, target]); + checkLastEntry(entries, 2, [8, 108, -42, 58, 0, 0, 0, 0, 0, 785, 0, 600, false]); document.scrollingElement.scrollTop = 0; } </script>
diff --git a/third_party/WebKit/LayoutTests/intersection-observer/multiple-thresholds.html b/third_party/WebKit/LayoutTests/intersection-observer/multiple-thresholds.html index 03ea9bd..bfab2b4 100644 --- a/third_party/WebKit/LayoutTests/intersection-observer/multiple-thresholds.html +++ b/third_party/WebKit/LayoutTests/intersection-observer/multiple-thresholds.html
@@ -44,53 +44,53 @@ function step0() { document.scrollingElement.scrollTop = 120; runTestCycle(step1, "document.scrollingElement.scrollTop = 120"); - checkLastEntry(entries, 0, [8, 108, 708, 808, 0, 0, 0, 0, 0, 785, 0, 600, target]); + checkLastEntry(entries, 0, [8, 108, 708, 808, 0, 0, 0, 0, 0, 785, 0, 600, false]); } function step1() { document.scrollingElement.scrollTop = 160; runTestCycle(step2, "document.scrollingElement.scrollTop = 160"); - checkLastEntry(entries, 1, [8, 108, 588, 688, 8, 108, 588, 600, 0, 785, 0, 600, target]); + checkLastEntry(entries, 1, [8, 108, 588, 688, 8, 108, 588, 600, 0, 785, 0, 600, true]); } function step2() { document.scrollingElement.scrollTop = 200; runTestCycle(step3, "document.scrollingElement.scrollTop = 200"); - checkLastEntry(entries, 2, [8, 108, 548, 648, 8, 108, 548, 600, 0, 785, 0, 600, target]); + checkLastEntry(entries, 2, [8, 108, 548, 648, 8, 108, 548, 600, 0, 785, 0, 600, true]); } function step3() { document.scrollingElement.scrollTop = 240; runTestCycle(step4, "document.scrollingElement.scrollTop = 240"); - checkLastEntry(entries, 3, [8, 108, 508, 608, 8, 108, 508, 600, 0, 785, 0, 600, target]); + checkLastEntry(entries, 3, [8, 108, 508, 608, 8, 108, 508, 600, 0, 785, 0, 600, true]); } function step4() { document.scrollingElement.scrollTop = 740; runTestCycle(step5, "document.scrollingElement.scrollTop = 740"); - checkLastEntry(entries, 4, [8, 108, 468, 568, 8, 108, 468, 568, 0, 785, 0, 600, target]); + checkLastEntry(entries, 4, [8, 108, 468, 568, 8, 108, 468, 568, 0, 785, 0, 600, true]); } function step5() { document.scrollingElement.scrollTop = 760; runTestCycle(step6, "document.scrollingElement.scrollTop = 760"); - checkLastEntry(entries, 5, [8, 108, -32, 68, 8, 108, 0, 68, 0, 785, 0, 600, target]); + checkLastEntry(entries, 5, [8, 108, -32, 68, 8, 108, 0, 68, 0, 785, 0, 600, true]); } function step6() { document.scrollingElement.scrollTop = 800; runTestCycle(step7, "document.scrollingElement.scrollTop = 800"); - checkLastEntry(entries, 6, [8, 108, -52, 48, 8, 108, 0, 48, 0, 785, 0, 600, target]); + checkLastEntry(entries, 6, [8, 108, -52, 48, 8, 108, 0, 48, 0, 785, 0, 600, true]); } function step7() { - checkLastEntry(entries, 7, [8, 108, -92, 8, 8, 108, 0, 8, 0, 785, 0, 600, target]); + checkLastEntry(entries, 7, [8, 108, -92, 8, 8, 108, 0, 8, 0, 785, 0, 600, true]); document.scrollingElement.scrollTop = 820; runTestCycle(step8, "document.scrollingElement.scrollTop = 820"); } function step8() { - checkLastEntry(entries, 8, [8, 108, -112, -12, 0, 0, 0, 0, 0, 785, 0, 600, target]); + checkLastEntry(entries, 8, [8, 108, -112, -12, 0, 0, 0, 0, 0, 785, 0, 600, false]); document.scrollingElement.scrollTop = 0; } </script>
diff --git a/third_party/WebKit/LayoutTests/intersection-observer/remove-element.html b/third_party/WebKit/LayoutTests/intersection-observer/remove-element.html index f60aa23..0417814 100644 --- a/third_party/WebKit/LayoutTests/intersection-observer/remove-element.html +++ b/third_party/WebKit/LayoutTests/intersection-observer/remove-element.html
@@ -57,20 +57,20 @@ function step0() { root.scrollTop = 150; runTestCycle(step1, "root.scrollTop = 150"); - checkLastEntry(entries, 0, [11, 111, 311, 411, 0, 0, 0, 0, 11, 111, 11, 211, target]); + checkLastEntry(entries, 0, [11, 111, 311, 411, 0, 0, 0, 0, 11, 111, 11, 211, false]); } function step1() { root.removeChild(target); runTestCycle(step2, "root.removeChild(target)."); - checkLastEntry(entries, 1, [11, 111, 161, 261, 11, 111, 161, 211, 11, 111, 11, 211, target]); + checkLastEntry(entries, 1, [11, 111, 161, 261, 11, 111, 161, 211, 11, 111, 11, 211, true]); } function step2() { root.scrollTop = 0; root.insertBefore(target, trailingSpace); runTestCycle(step3, "root.insertBefore(target, trailingSpace)."); - checkLastEntry(entries, 2, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, target]); + checkLastEntry(entries, 2, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false]); } function step3() { @@ -80,6 +80,6 @@ } function step4() { - checkLastEntry(entries, 3, [11, 111, 161, 261, 11, 111, 161, 211, 11, 111, 11, 211, target]); + checkLastEntry(entries, 3, [11, 111, 161, 261, 11, 111, 161, 211, 11, 111, 11, 211, true]); } </script>
diff --git a/third_party/WebKit/LayoutTests/intersection-observer/resources/intersection-observer-test-utils.js b/third_party/WebKit/LayoutTests/intersection-observer/resources/intersection-observer-test-utils.js index f9eca2e..f3285640 100644 --- a/third_party/WebKit/LayoutTests/intersection-observer/resources/intersection-observer-test-utils.js +++ b/third_party/WebKit/LayoutTests/intersection-observer/resources/intersection-observer-test-utils.js
@@ -86,6 +86,11 @@ checkRect( entries[i].rootBounds, expected.slice(8, 12), 'entries[' + i + '].rootBounds'); + if (expected.length > 12) { + assert_equals( + entries[i].isIntersecting, expected[12], + 'entries[' + i + '].isIntersecting'); + } } }
diff --git a/third_party/WebKit/LayoutTests/intersection-observer/resources/observer-in-iframe-subframe.html b/third_party/WebKit/LayoutTests/intersection-observer/resources/observer-in-iframe-subframe.html index ab19066..fda61960 100644 --- a/third_party/WebKit/LayoutTests/intersection-observer/resources/observer-in-iframe-subframe.html +++ b/third_party/WebKit/LayoutTests/intersection-observer/resources/observer-in-iframe-subframe.html
@@ -56,10 +56,10 @@ function step1() { scroller.scrollTop = 250; runTestCycle(step2, "scroller.scrollTop = 250"); - checkLastEntry(entries, 0, [8, 108, 308, 408, 0, 0, 0, 0, 8, 208, 8, 208, target]); + checkLastEntry(entries, 0, [8, 108, 308, 408, 0, 0, 0, 0, 8, 208, 8, 208, false]); } function step2() { - checkLastEntry(entries, 1, [8, 108, 58, 158, 8, 108, 58, 158, 8, 208, 8, 208, target]); + checkLastEntry(entries, 1, [8, 108, 58, 158, 8, 108, 58, 158, 8, 208, 8, 208, true]); } </script>
diff --git a/third_party/WebKit/LayoutTests/intersection-observer/root-margin.html b/third_party/WebKit/LayoutTests/intersection-observer/root-margin.html index 6ccd802..cbd3e15 100644 --- a/third_party/WebKit/LayoutTests/intersection-observer/root-margin.html +++ b/third_party/WebKit/LayoutTests/intersection-observer/root-margin.html
@@ -54,13 +54,13 @@ function step0() { document.scrollingElement.scrollLeft = 100; runTestCycle(step1, "document.scrollingElement.scrollLeft = 100"); - checkLastEntry(entries, 0, [1012, 1112, 708, 808, 0, 0, 0, 0, -30, 942, -10, 819, target]); + checkLastEntry(entries, 0, [1012, 1112, 708, 808, 0, 0, 0, 0, -30, 942, -10, 819, false]); } function step1() { document.scrollingElement.scrollTop = 800; runTestCycle(step2, "document.scrollingElement.scrollTop = 800"); - checkLastEntry(entries, 1, [912, 1012, 708, 808, 912, 942, 708, 808, -30, 942, -10, 819, target]); + checkLastEntry(entries, 1, [912, 1012, 708, 808, 912, 942, 708, 808, -30, 942, -10, 819, true]); } function step2() { @@ -72,6 +72,6 @@ function step3() { document.scrollingElement.scrollLeft = 0; document.scrollingElement.scrollTop = 0; - checkLastEntry(entries, 2, [912, 1012, -192, -92, 0, 0, 0, 0, -30, 942, -10, 819, target]); + checkLastEntry(entries, 2, [912, 1012, -192, -92, 0, 0, 0, 0, -30, 942, -10, 819, false]); } </script>
diff --git a/third_party/WebKit/LayoutTests/intersection-observer/same-document-no-root.html b/third_party/WebKit/LayoutTests/intersection-observer/same-document-no-root.html index 7ca9413..22b1616 100644 --- a/third_party/WebKit/LayoutTests/intersection-observer/same-document-no-root.html +++ b/third_party/WebKit/LayoutTests/intersection-observer/same-document-no-root.html
@@ -45,17 +45,17 @@ function step0() { document.scrollingElement.scrollTop = 300; runTestCycle(step1, "document.scrollingElement.scrollTop = 300"); - checkLastEntry(entries, 0, [8, 108, 708, 808, 0, 0, 0, 0, 0, 785, 0, 600, target]); + checkLastEntry(entries, 0, [8, 108, 708, 808, 0, 0, 0, 0, 0, 785, 0, 600, false]); } function step1() { document.scrollingElement.scrollTop = 100; runTestCycle(step2, "document.scrollingElement.scrollTop = 100"); - checkLastEntry(entries, 1, [8, 108, 408, 508, 8, 108, 408, 508, 0, 785, 0, 600, target]); + checkLastEntry(entries, 1, [8, 108, 408, 508, 8, 108, 408, 508, 0, 785, 0, 600, true]); } function step2() { document.scrollingElement.scrollTop = 0; - checkLastEntry(entries, 2, [8, 108, 608, 708, 0, 0, 0, 0, 0, 785, 0, 600, target]); + checkLastEntry(entries, 2, [8, 108, 608, 708, 0, 0, 0, 0, 0, 785, 0, 600, false]); } </script>
diff --git a/third_party/WebKit/LayoutTests/intersection-observer/same-document-root.html b/third_party/WebKit/LayoutTests/intersection-observer/same-document-root.html index 303d58d..727fbbc0 100644 --- a/third_party/WebKit/LayoutTests/intersection-observer/same-document-root.html +++ b/third_party/WebKit/LayoutTests/intersection-observer/same-document-root.html
@@ -56,7 +56,7 @@ function step0() { document.scrollingElement.scrollTop = 600; runTestCycle(step1, "document.scrollingElement.scrollTop = 600."); - checkLastEntry(entries, 0, [11, 111, 1011, 1111, 0, 0, 0, 0, 11, 111, 711, 911, target]); + checkLastEntry(entries, 0, [11, 111, 1011, 1111, 0, 0, 0, 0, 11, 111, 711, 911, false]); } function step1() { @@ -68,7 +68,7 @@ function step2() { document.scrollingElement.scrollTop = 0; runTestCycle(step3, "document.scrollingElement.scrollTop = 0."); - checkLastEntry(entries, 1, [11, 111, 261, 361, 11, 111, 261, 311, 11, 111, 111, 311, target]); + checkLastEntry(entries, 1, [11, 111, 261, 361, 11, 111, 261, 311, 11, 111, 111, 311, true]); } function step3() { @@ -80,11 +80,11 @@ function step4() { root.scrollTop = 150; runTestCycle(step5, "root.scrollTop = 150 with root scrolled out of view."); - checkLastEntry(entries, 2, [11, 111, 1011, 1111, 0, 0, 0, 0, 11, 111, 711, 911, target]); + checkLastEntry(entries, 2, [11, 111, 1011, 1111, 0, 0, 0, 0, 11, 111, 711, 911, false]); } // This tests that notifications are generated even when the root element is off screen. function step5() { - checkLastEntry(entries, 3, [11, 111, 861, 961, 11, 111, 861, 911, 11, 111, 711, 911, target]); + checkLastEntry(entries, 3, [11, 111, 861, 961, 11, 111, 861, 911, 11, 111, 711, 911, true]); } </script>
diff --git a/third_party/WebKit/LayoutTests/intersection-observer/same-document-zero-size-target.html b/third_party/WebKit/LayoutTests/intersection-observer/same-document-zero-size-target.html index b416553..a51410f 100644 --- a/third_party/WebKit/LayoutTests/intersection-observer/same-document-zero-size-target.html +++ b/third_party/WebKit/LayoutTests/intersection-observer/same-document-zero-size-target.html
@@ -45,17 +45,17 @@ function step0() { document.scrollingElement.scrollTop = 300; runTestCycle(step1, "document.scrollingElement.scrollTop = 300"); - checkLastEntry(entries, 0, [8, 8, 708, 708, 0, 0, 0, 0, 0, 785, 0, 600, target]); + checkLastEntry(entries, 0, [8, 8, 708, 708, 0, 0, 0, 0, 0, 785, 0, 600, false]); } function step1() { document.scrollingElement.scrollTop = 100; runTestCycle(step2, "document.scrollingElement.scrollTop = 100"); - checkLastEntry(entries, 1, [8, 8, 408, 408, 8, 8, 408, 408, 0, 785, 0, 600, target]); + checkLastEntry(entries, 1, [8, 8, 408, 408, 8, 8, 408, 408, 0, 785, 0, 600, true]); } function step2() { document.scrollingElement.scrollTop = 0; - checkLastEntry(entries, 2, [8, 8, 608, 608, 0, 0, 0, 0, 0, 785, 0, 600, target]); + checkLastEntry(entries, 2, [8, 8, 608, 608, 0, 0, 0, 0, 0, 785, 0, 600, false]); } </script>
diff --git a/third_party/WebKit/LayoutTests/intersection-observer/shadow-content.html b/third_party/WebKit/LayoutTests/intersection-observer/shadow-content.html index 8c211b97f..869dc1f8 100644 --- a/third_party/WebKit/LayoutTests/intersection-observer/shadow-content.html +++ b/third_party/WebKit/LayoutTests/intersection-observer/shadow-content.html
@@ -39,6 +39,6 @@ }, "Observing a target inside shadow DOM."); function step0() { - checkLastEntry(entries, 0, [8, 108, 8, 108, 8, 108, 8, 108, 0, 800, 0, 600, target]); + checkLastEntry(entries, 0, [8, 108, 8, 108, 8, 108, 8, 108, 0, 800, 0, 600, true]); } </script>
diff --git a/third_party/WebKit/LayoutTests/intersection-observer/unclipped-root.html b/third_party/WebKit/LayoutTests/intersection-observer/unclipped-root.html index 490b9eb..18e43d08 100644 --- a/third_party/WebKit/LayoutTests/intersection-observer/unclipped-root.html +++ b/third_party/WebKit/LayoutTests/intersection-observer/unclipped-root.html
@@ -47,11 +47,11 @@ function step0() { target.style.transform = "translateY(195px)"; runTestCycle(step1, "target.style.transform = 'translateY(195px)'"); - checkLastEntry(entries, 0, [15, 115, 315, 415, 0, 0, 0, 0, 8, 182, 8, 222, target]); + checkLastEntry(entries, 0, [15, 115, 315, 415, 0, 0, 0, 0, 8, 182, 8, 222, false]); } function step1() { target.style.transform = ""; - checkLastEntry(entries, 1, [15, 115, 210, 310, 15, 115, 210, 222, 8, 182, 8, 222, target]); + checkLastEntry(entries, 1, [15, 115, 210, 310, 15, 115, 210, 222, 8, 182, 8, 222, true]); } </script>
diff --git a/third_party/WebKit/LayoutTests/intersection-observer/zero-area-element-hidden.html b/third_party/WebKit/LayoutTests/intersection-observer/zero-area-element-hidden.html index 03d9efb..ce468071 100644 --- a/third_party/WebKit/LayoutTests/intersection-observer/zero-area-element-hidden.html +++ b/third_party/WebKit/LayoutTests/intersection-observer/zero-area-element-hidden.html
@@ -38,6 +38,6 @@ }, "A zero-area hidden target should not be intersecting."); function step0() { - checkLastEntry(entries, 0, [8, 8, -1000, -1000, 0, 0, 0, 0, 0, 800, 0, 600, target]); + checkLastEntry(entries, 0, [8, 8, -1000, -1000, 0, 0, 0, 0, 0, 800, 0, 600, false]); } </script>
diff --git a/third_party/WebKit/LayoutTests/media/color-profile-video-expected.png b/third_party/WebKit/LayoutTests/media/color-profile-video-expected.png index 40b164b..132ad68c 100644 --- a/third_party/WebKit/LayoutTests/media/color-profile-video-expected.png +++ b/third_party/WebKit/LayoutTests/media/color-profile-video-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/media/color-profile-video-seek-expected.png b/third_party/WebKit/LayoutTests/media/color-profile-video-seek-expected.png new file mode 100644 index 0000000..5b24f3e --- /dev/null +++ b/third_party/WebKit/LayoutTests/media/color-profile-video-seek-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/media/color-profile-video-seek-object-fit-expected.png b/third_party/WebKit/LayoutTests/media/color-profile-video-seek-object-fit-expected.png deleted file mode 100644 index a42b57c..0000000 --- a/third_party/WebKit/LayoutTests/media/color-profile-video-seek-object-fit-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/media/remoteplayback/availability-callback-gc.html b/third_party/WebKit/LayoutTests/media/remoteplayback/availability-callback-gc.html index da2e209e..f5fda80 100644 --- a/third_party/WebKit/LayoutTests/media/remoteplayback/availability-callback-gc.html +++ b/third_party/WebKit/LayoutTests/media/remoteplayback/availability-callback-gc.html
@@ -8,6 +8,9 @@ </head> <body> <script> + // WPT: this test can't be moved to WPT because of its usage of: + // - GCController.collect() + function gc() { if (window.GCController) GCController.collect();
diff --git a/third_party/WebKit/LayoutTests/media/remoteplayback/cancel-watch-availability.html b/third_party/WebKit/LayoutTests/media/remoteplayback/cancel-watch-availability.html deleted file mode 100644 index 1043a99..0000000 --- a/third_party/WebKit/LayoutTests/media/remoteplayback/cancel-watch-availability.html +++ /dev/null
@@ -1,61 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title>Tests various ways to call cancelWatchAvailability()</title> - <script src="../../resources/testharness.js"></script> - <script src="../../resources/testharnessreport.js"></script> - <script src="../media-file.js"></script> - </head> - <body> - <script> - var notFoundErrorException = new DOMException( - 'A callback with the given id is not found.', - 'NotFoundError'); - - async_test(function(t) { - var v = document.createElement('video'); - v.src = findMediaFile('video', 'content/test'); - document.body.appendChild(v); - - v.remote.watchAvailability(function() {}) - .then(t.step_func(function(id) { - v.remote.cancelWatchAvailability(id).then(t.step_func(function() { - v.remote.cancelWatchAvailability(id).then( - t.unreached_func(), t.step_func_done(function(e) { - assert_equals(e.name, notFoundErrorException.name); - assert_equals(e.message, notFoundErrorException.message); - }) - ); - }), - t.unreached_func()); - }), - t.unreached_func()); - }, 'Test that calling cancelWatchAvailability() with an id does remove the callback.'); - - async_test(function(t) { - var v = document.createElement('video'); - v.src = findMediaFile('video', 'content/test'); - document.body.appendChild(v); - - Promise.all([ - v.remote.watchAvailability(function() {}), - v.remote.watchAvailability(function() {}) - ]).then(t.step_func(function(ids) { - v.remote.cancelWatchAvailability().then(t.step_func(function() { - v.remote.cancelWatchAvailability(ids[0]).then(t.unreached_func(), t.step_func(function(e) { - assert_equals(e.name, notFoundErrorException.name); - assert_equals(e.message, notFoundErrorException.message); - v.remote.cancelWatchAvailability(ids[1]) - .then(t.unreached_func(), t.step_func_done(function(e) { - assert_equals(e.name, notFoundErrorException.name); - assert_equals(e.message, notFoundErrorException.message); - })); - })); - }), - t.unreached_func()); - }), - t.unreached_func()); - }, 'Test that calling cancelWatchAvailability() without an id removes all the callbacks.'); - </script> - </body> -</html>
diff --git a/third_party/WebKit/LayoutTests/media/remoteplayback/disable-remote-playback-cancel-watch-availability-throws.html b/third_party/WebKit/LayoutTests/media/remoteplayback/disable-remote-playback-cancel-watch-availability-throws.html deleted file mode 100644 index ad63fa9..0000000 --- a/third_party/WebKit/LayoutTests/media/remoteplayback/disable-remote-playback-cancel-watch-availability-throws.html +++ /dev/null
@@ -1,41 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title>Test that calling cancelWatchAvailability() when disableRemotePlayback attribute is set throws an exception</title> - <script src="../../resources/testharness.js"></script> - <script src="../../resources/testharnessreport.js"></script> - <script src="../media-file.js"></script> - </head> - <body> - <script> - async_test(function(t) - { - var v = document.createElement('video'); - var invalidStateErrorException = new DOMException( - 'disableRemotePlayback attribute is present.', - 'InvalidStateError'); - v.src = findMediaFile('video', 'content/test'); - document.body.appendChild(v); - - v.remote.watchAvailability(function() {}) - .then(function(id) { - v.disableRemotePlayback = true; - v.remote.cancelWatchAvailability(id).then( - t.unreached_func(), - t.step_func(function(e) { - assert_equals(e.name, invalidStateErrorException.name); - assert_equals(e.message, invalidStateErrorException.message); - v.remote.cancelWatchAvailability().then( - t.unreached_func(), - t.step_func_done(function(e) { - assert_equals(e.name, invalidStateErrorException.name); - assert_equals(e.message, invalidStateErrorException.message); - }) - ); - })); - }, - t.unreached_func()); - }, 'Test that calling cancelWatchAvailability() when disableRemotePlayback attribute is set throws an exception.'); - </script> - </body> -</html>
diff --git a/third_party/WebKit/LayoutTests/media/remoteplayback/disable-remote-playback-prompt-throws.html b/third_party/WebKit/LayoutTests/media/remoteplayback/disable-remote-playback-prompt-throws.html deleted file mode 100644 index 115d807..0000000 --- a/third_party/WebKit/LayoutTests/media/remoteplayback/disable-remote-playback-prompt-throws.html +++ /dev/null
@@ -1,25 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title>Test that calling prompt() when disableRemotePlayback attribute is set throws an exception</title> - <script src="../../resources/testharness.js"></script> - <script src="../../resources/testharnessreport.js"></script> - <script src="../media-file.js"></script> - </head> - <body> - <script> - promise_test(function(test) - { - var v = document.createElement('video'); - v.src = findMediaFile('video', 'content/test'); - v.disableRemotePlayback = true; - document.body.appendChild(v); - - return promise_rejects( - test, - new DOMException('disableRemotePlayback attribute is present.', 'InvalidStateError'), - v.remote.prompt()); - }, 'Test that calling prompt() when disableRemotePlayback attribute is set throws an exception.'); - </script> - </body> -</html>
diff --git a/third_party/WebKit/LayoutTests/media/remoteplayback/disable-remote-playback-watch-availability-throws.html b/third_party/WebKit/LayoutTests/media/remoteplayback/disable-remote-playback-watch-availability-throws.html deleted file mode 100644 index 4c360256..0000000 --- a/third_party/WebKit/LayoutTests/media/remoteplayback/disable-remote-playback-watch-availability-throws.html +++ /dev/null
@@ -1,25 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title>Test that calling watchAvailability() when disableRemotePlayback attribute is set throws an exception</title> - <script src="../../resources/testharness.js"></script> - <script src="../../resources/testharnessreport.js"></script> - <script src="../media-file.js"></script> - </head> - <body> - <script> - promise_test(function(test) - { - var v = document.createElement('video'); - v.src = findMediaFile('video', 'content/test'); - v.disableRemotePlayback = true; - document.body.appendChild(v); - - return promise_rejects( - test, - new DOMException('disableRemotePlayback attribute is present.', 'InvalidStateError'), - v.remote.watchAvailability(function() {})); - }, 'Test that calling watchAvailability() when disableRemotePlayback attribute is set throws an exception.'); - </script> - </body> -</html>
diff --git a/third_party/WebKit/LayoutTests/media/remoteplayback/prompt-twice-throws.html b/third_party/WebKit/LayoutTests/media/remoteplayback/prompt-twice-throws.html index bacf9a04..1f678dec 100644 --- a/third_party/WebKit/LayoutTests/media/remoteplayback/prompt-twice-throws.html +++ b/third_party/WebKit/LayoutTests/media/remoteplayback/prompt-twice-throws.html
@@ -9,6 +9,11 @@ <body> <button id="button">Click me</button> <script> + // WPT: this test can't be moved to WPT because of its usage of: + // - user gesture; + // - internals.mediaPlayerRemoteRouteAvailabilityChanged + + function clickOnElem(e) { eventSender.mouseMoveTo( e.offsetLeft + e.offsetWidth / 2,
diff --git a/third_party/WebKit/LayoutTests/media/remoteplayback/watch-availability-initial-callback.html b/third_party/WebKit/LayoutTests/media/remoteplayback/watch-availability-initial-callback.html deleted file mode 100644 index 67ffcd9a..0000000 --- a/third_party/WebKit/LayoutTests/media/remoteplayback/watch-availability-initial-callback.html +++ /dev/null
@@ -1,30 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title>Test that the callback is called once watchAvailability() resolves.</title> - <script src="../../resources/testharness.js"></script> - <script src="../../resources/testharnessreport.js"></script> - <script src="../media-file.js"></script> - </head> - <body> - <script> - async_test(function(t) - { - var v = document.createElement('video'); - v.src = findMediaFile('video', 'content/test'); - document.body.appendChild(v); - - var promiseResolved = false; - - function callback(available) { - assert_false(available); - assert_true(promiseResolved); - } - - v.remote.watchAvailability(t.step_func_done(callback)).then( - function() { promiseResolved = true; }, - t.unreached_func()); - }, 'Test that the callback is called once watchAvailability() resolves.'); - </script> - </body> -</html>
diff --git a/third_party/WebKit/LayoutTests/media/remoteplayback/watch-availability-throws-low-end-device.html b/third_party/WebKit/LayoutTests/media/remoteplayback/watch-availability-throws-low-end-device.html index b0dbb26..2e331ff7 100644 --- a/third_party/WebKit/LayoutTests/media/remoteplayback/watch-availability-throws-low-end-device.html +++ b/third_party/WebKit/LayoutTests/media/remoteplayback/watch-availability-throws-low-end-device.html
@@ -8,6 +8,8 @@ </head> <body> <script> + // WPT: this test can't be moved to WPT because of its usage of: + // - internals.setIsLowEndDevice() async_test(function(t) { var v = document.createElement('video');
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/button-inner-no-repaint.html b/third_party/WebKit/LayoutTests/paint/invalidation/button-inner-no-repaint.html index eedd35e..eb45682 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/button-inner-no-repaint.html +++ b/third_party/WebKit/LayoutTests/paint/invalidation/button-inner-no-repaint.html
@@ -13,4 +13,4 @@ height: 100px; } </style> -<button>Should not repaint on style change that doesn't change visual.</button> +<button>Should not repaint on style change that doesn't change visual.<br></button>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/caret-color-inline-expected.html b/third_party/WebKit/LayoutTests/paint/invalidation/caret-color-inline-expected.html new file mode 100644 index 0000000..25aee61 --- /dev/null +++ b/third_party/WebKit/LayoutTests/paint/invalidation/caret-color-inline-expected.html
@@ -0,0 +1,7 @@ +<!DOCTYPE html> +Tests color of caret changes with the 'color' style. Passes if caret is always in the came color as the text. +<div id="div" contenteditable="true" style="color: green; font-size: 50px">SAMPLE</div> +<script src="../../resources/run-after-layout-and-paint.js"></script> +<script> +div.focus(); +</script>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/caret-color-inline.html b/third_party/WebKit/LayoutTests/paint/invalidation/caret-color-inline.html new file mode 100644 index 0000000..7505b80 --- /dev/null +++ b/third_party/WebKit/LayoutTests/paint/invalidation/caret-color-inline.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +Tests color of caret changes with the 'color' style. Passes if caret is always in the came color as the text. +<div id="div" contenteditable="true"> + <span id="span" style="color: red; font-size: 50px">SAMPLE</span> +</div> +<script src="../../resources/run-after-layout-and-paint.js"></script> +<script> +div.focus(); +runAfterLayoutAndPaint(function() { + span.style.color = 'green'; +}, true); +</script>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-caret-before-text-node-update-expected.png b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-caret-before-text-node-update-expected.png new file mode 100644 index 0000000..2495079 --- /dev/null +++ b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-caret-before-text-node-update-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-caret-before-text-node-update-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-caret-before-text-node-update-expected.txt new file mode 100644 index 0000000..f90b43e6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-caret-before-text-node-update-expected.txt
@@ -0,0 +1,37 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='root' class='editing'", + "rect": [7, 7, 786, 20], + "reason": "full" + }, + { + "object": "LayoutText #text", + "rect": [8, 8, 10, 18], + "reason": "layoutObject removal" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV id='root' class='editing'", + "reason": "full" + }, + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-caret-before-text-node-update.html b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-caret-before-text-node-update.html index fb6ade7..8e5c2676 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-caret-before-text-node-update.html +++ b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-caret-before-text-node-update.html
@@ -1,33 +1,21 @@ <!doctype HTML> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> +<script src="resources/text-based-repaint.js"></script> <div contenteditable id="root" class="editing"></div> <style> * { - font-family: Courier New; + font-family: Courier New; } </style> <script> -test(function() { - // The innerText must be set explicitly, and not with an editing command. - root.innerText = "1"; - window.getSelection().collapse(root.firstChild, 1); +onload = function() { + // The innerText must be set explicitly, and not with an editing command. + root.innerText = "1"; + window.getSelection().collapse(root.firstChild, 1); + + runRepaintAndPixelTest(); +}; - if (window.internals) - window.internals.startTrackingRepaints(document); - - debugger; - document.execCommand('delete'); - - if (window.internals) { - var layers = JSON.parse(window.internals.layerTreeAsText(document, internals.LAYER_TREE_INCLUDES_PAINT_INVALIDATIONS))["layers"] - assert_equals(layers[0].paintInvalidations[2].reason, "invalidate paint rectangle"); - var previousOffset = layers[0].paintInvalidations[2].rect[0]; - assert_equals(layers[0].paintInvalidations[2].rect[3], 20, "Old caret rect location"); - - assert_equals(layers[0].paintInvalidations[3].reason, "invalidate paint rectangle"); - // Check that thet x offset is previousOffset - 1. This for the caret rect after delete. - assert_not_equals(layers[0].paintInvalidations[3].rect[0], previousOffset, "New caret rect location"); - } -}); +function repaintTest() { + document.execCommand('delete'); +} </script>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/paint-caret-in-div-with-negative-indent-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/paint-caret-in-div-with-negative-indent-expected.txt index d9087f7..4126158 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/paint-caret-in-div-with-negative-indent-expected.txt +++ b/third_party/WebKit/LayoutTests/paint/invalidation/paint-caret-in-div-with-negative-indent-expected.txt
@@ -8,8 +8,8 @@ "paintInvalidations": [ { "object": "LayoutBlockFlow DIV id='editable'", - "rect": [357, 199, 3, 22], - "reason": "invalidate paint rectangle" + "rect": [358, 200, 1, 20], + "reason": "caret" } ] } @@ -17,7 +17,7 @@ "objectPaintInvalidations": [ { "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/video-fixed-scrolling-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/video-fixed-scrolling-expected.png index 543820f..abb4598 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/video-fixed-scrolling-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/video-fixed-scrolling-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/video-opacity-overlay-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/video-opacity-overlay-expected.png index 8d95fc8..d00a7a7 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/video-opacity-overlay-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/video-opacity-overlay-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/layers-inside-overflow-scroll-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/layers-inside-overflow-scroll-expected.png index 5d1282b..1b1bdbe 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/compositing/layers-inside-overflow-scroll-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/layers-inside-overflow-scroll-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/overflow-compositing-descendant-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/overflow-compositing-descendant-expected.png index b8ab72c0..d90e5e4 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/overflow-compositing-descendant-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/overflow-compositing-descendant-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/scroll-ancestor-update-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/scroll-ancestor-update-expected.png index acf834c0..9f698bd 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/scroll-ancestor-update-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/scroll-ancestor-update-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/reflections/load-video-in-reflection-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/reflections/load-video-in-reflection-expected.png index b916307a..953b1554 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/compositing/reflections/load-video-in-reflection-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/reflections/load-video-in-reflection-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/self-painting-layers-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/self-painting-layers-expected.png index 3614162..f16985e 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/compositing/self-painting-layers-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/self-painting-layers-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/video-frame-size-change-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/video-frame-size-change-expected.png index 25faa31..024892a 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/compositing/video-frame-size-change-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/video-frame-size-change-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/video/video-reflection-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/video/video-reflection-expected.png new file mode 100644 index 0000000..635d07ac --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/video/video-reflection-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/visibility/visibility-simple-video-layer-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/visibility/visibility-simple-video-layer-expected.png index 0358adb..13255e5 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/compositing/visibility/visibility-simple-video-layer-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/visibility/visibility-simple-video-layer-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-side-reduction-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-side-reduction-expected.png index bda0ada..67937608 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-side-reduction-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-side-reduction-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-expected.png index e0e1f8f..48d83e2 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-ratio-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-ratio-expected.png index 6f29caba..d253b5f 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-ratio-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-ratio-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-shadow-expected.png index eae687a3..fe8a15c 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-shadow-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-shadow-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-video-seek-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-video-seek-expected.png deleted file mode 100644 index f60f9a7f..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-video-seek-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-video-seek-filter-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-video-seek-filter-expected.png index 7ea462b..2b5e0b3 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-video-seek-filter-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-video-seek-filter-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-video-seek-object-fit-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-video-seek-object-fit-expected.png new file mode 100644 index 0000000..c4a1a2f --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/media/color-profile-video-seek-object-fit-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/track/track-cue-rendering-horizontal-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/track/track-cue-rendering-horizontal-expected.png index d465793..4c72bdc 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/track/track-cue-rendering-horizontal-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/track/track-cue-rendering-horizontal-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/track/track-cue-rendering-vertical-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/track/track-cue-rendering-vertical-expected.png index 9272bd8..47e3ef5 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/track/track-cue-rendering-vertical-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/track/track-cue-rendering-vertical-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-aspect-ratio-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/video-aspect-ratio-expected.png index 297246d..03da937 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-aspect-ratio-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-aspect-ratio-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-canvas-alpha-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/video-canvas-alpha-expected.png index 5d02b16..6af9546 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-canvas-alpha-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-canvas-alpha-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-colorspace-yuv420-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/video-colorspace-yuv420-expected.png index dd33900..a38eac4 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-colorspace-yuv420-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-colorspace-yuv420-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-colorspace-yuv422-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/video-colorspace-yuv422-expected.png index be2ea19..9afee1f 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-colorspace-yuv422-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-colorspace-yuv422-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-layer-crash-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/video-layer-crash-expected.png index b9ac197d..226d7e7f 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-layer-crash-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-layer-crash-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-overlay-cast-dark-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/video-overlay-cast-dark-rendering-expected.png index 1e717487..a3826acf 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-overlay-cast-dark-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-overlay-cast-dark-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-overlay-cast-light-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/video-overlay-cast-light-rendering-expected.png index 3622a16b..2e37088 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-overlay-cast-light-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-overlay-cast-light-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-remove-insert-repaints-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/video-remove-insert-repaints-expected.png index b12a3ac6..47efc6a 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-remove-insert-repaints-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-remove-insert-repaints-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-replaces-poster-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/video-replaces-poster-expected.png index 6c444912..5f79c3c 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-replaces-poster-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-replaces-poster-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-transformed-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/video-transformed-expected.png index 30d2dcfd..80f0830 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-transformed-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-transformed-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.png index 5911e2b..3204f9a 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-expected.png index 64aca40..dc914b2 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/4776765-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/4776765-expected.txt index a7066440..bf3323c 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/4776765-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/4776765-expected.txt
@@ -18,37 +18,14 @@ }, { "object": "LayoutBlockFlow DIV id='div'", - "rect": [7, 83, 3, 21], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='div'", - "rect": [7, 83, 3, 21], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='div'", - "rect": [7, 83, 3, 21], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='div'", - "rect": [7, 63, 3, 21], - "reason": "invalidate paint rectangle" + "rect": [8, 64, 1, 19], + "reason": "caret" } ] } ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV", "reason": "border box change" }, @@ -62,11 +39,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutBR BR",
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/bugzilla-6473-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/bugzilla-6473-expected.txt index 561cb063..7207655 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/bugzilla-6473-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/bugzilla-6473-expected.txt
@@ -14,22 +14,22 @@ { "object": "LayoutBlockFlow (relative positioned) P", "rect": [8, 152, 784, 20], - "reason": "bounds change" + "reason": "forced by layout" }, { "object": "LayoutBlockFlow (relative positioned) P", "rect": [8, 136, 784, 20], - "reason": "bounds change" + "reason": "forced by layout" }, { "object": "LayoutText #text", "rect": [8, 152, 69, 19], - "reason": "bounds change" + "reason": "forced by layout" }, { "object": "LayoutText #text", "rect": [8, 136, 69, 19], - "reason": "bounds change" + "reason": "forced by layout" } ] } @@ -41,19 +41,19 @@ }, { "object": "LayoutBlockFlow (relative positioned) P", - "reason": "bounds change" + "reason": "forced by layout" }, { "object": "RootInlineBox", - "reason": "bounds change" + "reason": "forced by layout" }, { "object": "LayoutText #text", - "reason": "bounds change" + "reason": "forced by layout" }, { "object": "InlineTextBox 'SUCCESS'", - "reason": "bounds change" + "reason": "forced by layout" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-contenteditable-content-after-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-contenteditable-content-after-expected.txt index 3369299..020d385 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-contenteditable-content-after-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-contenteditable-content-after-expected.txt
@@ -70,91 +70,12 @@ "object": "LayoutTextFragment (anonymous)", "rect": [8, 48, 7, 19], "reason": "forced by layout" - }, - { - "object": "LayoutBlockFlow DIV id='editor'", - "rect": [7, 47, 3, 22], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='editor'", - "rect": [7, 47, 3, 22], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='editor'", - "rect": [7, 47, 3, 22], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='editor'", - "rect": [7, 47, 3, 22], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [29, 47, 3, 21], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [29, 47, 3, 21], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [29, 47, 3, 21], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [22, 47, 3, 21], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [22, 47, 3, 21], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [22, 47, 3, 21], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [22, 47, 3, 21], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [14, 47, 3, 21], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [14, 47, 3, 21], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [14, 47, 3, 21], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [14, 47, 3, 21], - "reason": "invalidate paint rectangle" } ] } ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV id='editor'", "reason": "style change" }, @@ -164,19 +85,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutBlockFlow DIV id='editor'", @@ -188,11 +97,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutText #text", @@ -211,14 +116,6 @@ "reason": "forced by layout" }, { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV id='editor'", "reason": "forced by layout" }, @@ -228,11 +125,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutText #text", @@ -251,14 +144,6 @@ "reason": "forced by layout" }, { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV id='editor'", "reason": "forced by layout" }, @@ -268,11 +153,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt index e4770a0..9ec59101 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt
@@ -7,14 +7,14 @@ "drawsContent": true, "paintInvalidations": [ { - "object": "LayoutText #text", - "rect": [380, 11, 3, 16], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [381, 11, 1, 16], + "reason": "caret" }, { - "object": "LayoutText #text", - "rect": [377, 11, 3, 16], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [378, 11, 1, 16], + "reason": "caret" } ] } @@ -22,11 +22,7 @@ "objectPaintInvalidations": [ { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-outside-block-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-outside-block-expected.txt index 262849ab..b8644c03 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-outside-block-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-outside-block-expected.txt
@@ -7,9 +7,9 @@ "drawsContent": true, "paintInvalidations": [ { - "object": "LayoutText #text", - "rect": [790, 7, 3, 21], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='target'", + "rect": [791, 8, 1, 19], + "reason": "caret" } ] } @@ -17,7 +17,7 @@ "objectPaintInvalidations": [ { "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-with-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-with-composited-scroll-expected.txt index 772ec9e..d341afd0 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-with-composited-scroll-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-with-composited-scroll-expected.txt
@@ -32,21 +32,6 @@ "object": "LayoutBlockFlow DIV id='inner-editor'", "rect": [3, 1003, 200, 16], "reason": "subtree" - }, - { - "object": "LayoutBlockFlow DIV id='inner-editor'", - "rect": [2, 1002, 3, 18], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='inner-editor'", - "rect": [2, 1002, 3, 18], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='inner-editor'", - "rect": [2, 1002, 3, 18], - "reason": "invalidate paint rectangle" } ] }, @@ -69,10 +54,6 @@ ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutTextControl INPUT id='text'", "reason": "subtree" }, @@ -82,11 +63,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-with-transformation-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-with-transformation-expected.txt index daf97a2..5530feac 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-with-transformation-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-with-transformation-expected.txt
@@ -7,14 +7,14 @@ "drawsContent": true, "paintInvalidations": [ { - "object": "LayoutText #text", - "rect": [322, 197, 14, 21], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='div'", + "rect": [42, 36, 11, 18], + "reason": "caret" }, { - "object": "LayoutText #text", - "rect": [41, 35, 14, 20], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='div'", + "rect": [324, 199, 11, 17], + "reason": "caret" } ] } @@ -22,11 +22,7 @@ "objectPaintInvalidations": [ { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/delete-into-nested-block-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/delete-into-nested-block-expected.txt index c123fdc..ff84e0cf 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/delete-into-nested-block-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/delete-into-nested-block-expected.txt
@@ -45,21 +45,6 @@ "object": "LayoutText #text", "rect": [8, 127, 26, 20], "reason": "layoutObject removal" - }, - { - "object": "LayoutText #text", - "rect": [7, 126, 3, 22], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [7, 126, 3, 22], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [7, 126, 3, 22], - "reason": "invalidate paint rectangle" } ] } @@ -106,10 +91,6 @@ "reason": "layoutObject removal" }, { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV id='one'", "reason": "full" }, @@ -119,11 +100,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/inline-outline-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/inline-outline-repaint-expected.txt index 019a400d..4f6a48f 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/inline-outline-repaint-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/inline-outline-repaint-expected.txt
@@ -20,21 +20,6 @@ "object": "LayoutText #text", "rect": [8, 156, 86, 39], "reason": "full" - }, - { - "object": "LayoutText #text", - "rect": [43, 175, 3, 21], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [43, 175, 3, 21], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [43, 175, 3, 21], - "reason": "invalidate paint rectangle" } ] } @@ -45,10 +30,6 @@ "reason": "layoutObject removal" }, { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV", "reason": "forced by layout" }, @@ -58,11 +39,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutInline SPAN id='test'",
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt index 745f58c7..ce066969 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -43,9 +43,9 @@ "drawsContent": true, "paintInvalidations": [ { - "object": "LayoutText #text", - "rect": [72, -1, 3, 18], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [73, 0, 1, 16], + "reason": "caret" } ] }, @@ -62,12 +62,12 @@ ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutTextControl INPUT id='root'", "reason": "subtree" + }, + { + "object": "Caret", + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt index 867e2e5..f6045d1 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
@@ -32,31 +32,12 @@ "object": "LayoutText #text", "rect": [3, 4, 60, 16], "reason": "subtree" - }, - { - "object": "LayoutText #text", - "rect": [60, 4, 3, 16], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [60, 4, 3, 16], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [60, 4, 3, 16], - "reason": "invalidate paint rectangle" } ] } ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutTextControl INPUT id='root'", "reason": "subtree" }, @@ -74,11 +55,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/selection-after-delete-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/selection-after-delete-expected.txt index eb5e0277..4d9c6c8 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/selection-after-delete-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/selection-after-delete-expected.txt
@@ -15,21 +15,6 @@ "object": "LayoutText #text", "rect": [39, 79, 146, 99], "reason": "layoutObject removal" - }, - { - "object": "LayoutBlockFlow DIV id='test'", - "rect": [38, 78, 3, 21], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='test'", - "rect": [38, 78, 3, 21], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='test'", - "rect": [38, 78, 3, 21], - "reason": "invalidate paint rectangle" } ] } @@ -40,10 +25,6 @@ "reason": "layoutObject removal" }, { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV id='test'", "reason": "forced by layout" }, @@ -53,11 +34,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutBR BR",
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/tabgroup-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/tabgroup-expected.txt index 8b00c58..4de4504d 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/tabgroup-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/tabgroup-expected.txt
@@ -986,6 +986,42 @@ "reason": "layoutObject removal" }, { + "object": "LayoutSVGPath path", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGPath path id='tabgroupTriangle__0'", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGInlineText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGTSpan tspan", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGInlineText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGTSpan tspan", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGText text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGContainer g id='tabgroupTriangle__0_content'", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGContainer g", + "reason": "layoutObject removal" + }, + { "object": "LayoutSVGContainer g id='tabgroupRect'", "reason": "became visible" },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/full-screen-iframe-allowed-video-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/full-screen-iframe-allowed-video-expected.png index 0646082..1a76169 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/full-screen-iframe-allowed-video-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/full-screen-iframe-allowed-video-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-controls-timeline-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-controls-timeline-expected.png index 0646082..1a76169 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-controls-timeline-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-controls-timeline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-scrolled-iframe-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-scrolled-iframe-expected.png index 0646082..1a76169 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-scrolled-iframe-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-scrolled-iframe-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/4776765-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/4776765-expected.txt new file mode 100644 index 0000000..bf3323c --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/4776765-expected.txt
@@ -0,0 +1,54 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV", + "rect": [7, 43, 786, 62], + "reason": "border box change" + }, + { + "object": "LayoutBlockFlow DIV id='div'", + "rect": [8, 84, 784, 20], + "reason": "layoutObject insertion" + }, + { + "object": "LayoutBlockFlow DIV id='div'", + "rect": [8, 64, 1, 19], + "reason": "caret" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutBlockFlow DIV", + "reason": "border box change" + }, + { + "object": "LayoutBlockFlow DIV id='div'", + "reason": "layoutObject insertion" + }, + { + "object": "RootInlineBox", + "reason": "layoutObject insertion" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutBR BR", + "reason": "layoutObject insertion" + }, + { + "object": "InlineTextBox '\n'", + "reason": "layoutObject insertion" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/caret-contenteditable-content-after-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/caret-contenteditable-content-after-expected.txt new file mode 100644 index 0000000..020d385 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/caret-contenteditable-content-after-expected.txt
@@ -0,0 +1,176 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='editor'", + "rect": [7, 47, 786, 22], + "reason": "style change" + }, + { + "object": "LayoutBlockFlow DIV id='editor'", + "rect": [7, 47, 786, 22], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow DIV id='editor'", + "rect": [7, 47, 786, 22], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow DIV id='editor'", + "rect": [7, 47, 786, 22], + "reason": "forced by layout" + }, + { + "object": "LayoutText #text", + "rect": [8, 48, 22, 19], + "reason": "full" + }, + { + "object": "LayoutText #text", + "rect": [8, 48, 15, 19], + "reason": "full" + }, + { + "object": "LayoutTextFragment (anonymous)", + "rect": [30, 48, 7, 19], + "reason": "forced by layout" + }, + { + "object": "LayoutTextFragment (anonymous)", + "rect": [23, 48, 7, 19], + "reason": "forced by layout" + }, + { + "object": "LayoutTextFragment (anonymous)", + "rect": [23, 48, 7, 19], + "reason": "forced by layout" + }, + { + "object": "LayoutTextFragment (anonymous)", + "rect": [15, 48, 7, 19], + "reason": "forced by layout" + }, + { + "object": "LayoutTextFragment (anonymous)", + "rect": [15, 48, 7, 19], + "reason": "forced by layout" + }, + { + "object": "LayoutText #text", + "rect": [8, 48, 7, 19], + "reason": "layoutObject insertion" + }, + { + "object": "LayoutTextFragment (anonymous)", + "rect": [8, 48, 7, 19], + "reason": "forced by layout" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='editor'", + "reason": "style change" + }, + { + "object": "RootInlineBox", + "reason": "style change" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutBlockFlow DIV id='editor'", + "reason": "forced by layout" + }, + { + "object": "RootInlineBox", + "reason": "forced by layout" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutText #text", + "reason": "layoutObject insertion" + }, + { + "object": "InlineTextBox 'a'", + "reason": "layoutObject insertion" + }, + { + "object": "LayoutTextFragment (anonymous)", + "reason": "forced by layout" + }, + { + "object": "InlineTextBox 'x'", + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow DIV id='editor'", + "reason": "forced by layout" + }, + { + "object": "RootInlineBox", + "reason": "forced by layout" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutText #text", + "reason": "full" + }, + { + "object": "InlineTextBox 'ab'", + "reason": "full" + }, + { + "object": "LayoutTextFragment (anonymous)", + "reason": "forced by layout" + }, + { + "object": "InlineTextBox 'x'", + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow DIV id='editor'", + "reason": "forced by layout" + }, + { + "object": "RootInlineBox", + "reason": "forced by layout" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutText #text", + "reason": "full" + }, + { + "object": "InlineTextBox 'abc'", + "reason": "full" + }, + { + "object": "LayoutTextFragment (anonymous)", + "reason": "forced by layout" + }, + { + "object": "InlineTextBox 'x'", + "reason": "forced by layout" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt new file mode 100644 index 0000000..9ec59101 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt
@@ -0,0 +1,29 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [381, 11, 1, 16], + "reason": "caret" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [378, 11, 1, 16], + "reason": "caret" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/caret-outside-block-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/caret-outside-block-expected.txt new file mode 100644 index 0000000..b8644c03 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/caret-outside-block-expected.txt
@@ -0,0 +1,24 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='target'", + "rect": [791, 8, 1, 19], + "reason": "caret" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll-expected.txt new file mode 100644 index 0000000..d341afd0 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll-expected.txt
@@ -0,0 +1,70 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true + }, + { + "name": "LayoutBlockFlow DIV id='scroller'", + "position": [8, 48], + "bounds": [100, 100], + "shouldFlattenTransform": false, + "drawsContent": true + }, + { + "name": "Scrolling Layer", + "bounds": [100, 100], + "shouldFlattenTransform": false + }, + { + "name": "Scrolling Contents Layer", + "bounds": [205, 1022], + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='text'", + "rect": [-1, 999, 207, 24], + "reason": "subtree" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [3, 1003, 200, 16], + "reason": "subtree" + } + ] + }, + { + "name": "Overflow Controls Host Layer", + "bounds": [100, 100] + }, + { + "name": "Horizontal Scrollbar Layer", + "position": [0, 100], + "bounds": [100, 0], + "drawsContent": true + }, + { + "name": "Vertical Scrollbar Layer", + "position": [100, 0], + "bounds": [0, 100], + "drawsContent": true + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='text'", + "reason": "subtree" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "reason": "subtree" + }, + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/caret-with-transformation-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/caret-with-transformation-expected.txt new file mode 100644 index 0000000..5530feac --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/caret-with-transformation-expected.txt
@@ -0,0 +1,29 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='div'", + "rect": [42, 36, 11, 18], + "reason": "caret" + }, + { + "object": "LayoutBlockFlow DIV id='div'", + "rect": [324, 199, 11, 17], + "reason": "caret" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/delete-into-nested-block-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/delete-into-nested-block-expected.txt new file mode 100644 index 0000000..ff84e0cf --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/delete-into-nested-block-expected.txt
@@ -0,0 +1,115 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='two'", + "rect": [8, 147, 784, 41], + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV", + "rect": [8, 167, 784, 21], + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV", + "rect": [8, 147, 784, 21], + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV id='one'", + "rect": [8, 127, 784, 21], + "reason": "full" + }, + { + "object": "LayoutText #text", + "rect": [8, 167, 30, 20], + "reason": "layoutObject removal" + }, + { + "object": "LayoutText #text", + "rect": [8, 127, 30, 20], + "reason": "layoutObject insertion" + }, + { + "object": "LayoutText #text", + "rect": [8, 147, 27, 20], + "reason": "layoutObject removal" + }, + { + "object": "LayoutText #text", + "rect": [8, 127, 26, 20], + "reason": "layoutObject removal" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV", + "reason": "layoutObject removal" + }, + { + "object": "LayoutText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBR BR", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV id='two'", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBR BR", + "reason": "layoutObject removal" + }, + { + "object": "LayoutText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutInline SPAN", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV id='one'", + "reason": "full" + }, + { + "object": "RootInlineBox", + "reason": "full" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutText #text", + "reason": "layoutObject insertion" + }, + { + "object": "InlineTextBox 'three'", + "reason": "layoutObject insertion" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/inline-outline-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/inline-outline-repaint-expected.txt index 019a400d..4f6a48f 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/inline-outline-repaint-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/inline-outline-repaint-expected.txt
@@ -20,21 +20,6 @@ "object": "LayoutText #text", "rect": [8, 156, 86, 39], "reason": "full" - }, - { - "object": "LayoutText #text", - "rect": [43, 175, 3, 21], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [43, 175, 3, 21], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [43, 175, 3, 21], - "reason": "invalidate paint rectangle" } ] } @@ -45,10 +30,6 @@ "reason": "layoutObject removal" }, { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV", "reason": "forced by layout" }, @@ -58,11 +39,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutInline SPAN id='test'",
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt new file mode 100644 index 0000000..ce066969 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -0,0 +1,74 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true + }, + { + "name": "LayoutTextControl INPUT id='root'", + "position": [7, 7], + "bounds": [66, 24], + "drawsContent": true, + "backgroundColor": "#FFFFFF", + "paintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='root'", + "rect": [0, 0, 66, 24], + "reason": "subtree" + }, + { + "object": "LayoutTextControl INPUT id='root'", + "rect": [0, 0, 64, 22], + "reason": "full" + } + ] + }, + { + "name": "LayoutBlockFlow DIV id='inner-editor'", + "position": [3, 4], + "bounds": [60, 16], + "shouldFlattenTransform": false, + "drawsContent": true + }, + { + "name": "Scrolling Layer", + "bounds": [60, 16], + "shouldFlattenTransform": false + }, + { + "name": "Scrolling Contents Layer", + "bounds": [75, 16], + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [73, 0, 1, 16], + "reason": "caret" + } + ] + }, + { + "name": "Overflow Controls Host Layer", + "bounds": [60, 16] + }, + { + "name": "Horizontal Scrollbar Layer", + "position": [0, 16], + "bounds": [60, 0], + "drawsContent": true + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='root'", + "reason": "subtree" + }, + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt new file mode 100644 index 0000000..f6045d1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
@@ -0,0 +1,70 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true + }, + { + "name": "LayoutTextControl INPUT id='root'", + "position": [7, 7], + "bounds": [66, 24], + "drawsContent": true, + "backgroundColor": "#FFFFFF", + "paintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='root'", + "rect": [0, 0, 66, 24], + "reason": "subtree" + }, + { + "object": "LayoutTextControl INPUT id='root'", + "rect": [0, 0, 64, 22], + "reason": "full" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [3, 4, 60, 16], + "reason": "subtree" + }, + { + "object": "LayoutText #text", + "rect": [3, 4, 60, 16], + "reason": "subtree" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='root'", + "reason": "subtree" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "reason": "subtree" + }, + { + "object": "RootInlineBox", + "reason": "subtree" + }, + { + "object": "HorizontalScrollbar", + "reason": "scroll" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutText #text", + "reason": "subtree" + }, + { + "object": "InlineTextBox 'test test test'", + "reason": "subtree" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/selection-after-delete-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/selection-after-delete-expected.txt new file mode 100644 index 0000000..4d9c6c8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/selection-after-delete-expected.txt
@@ -0,0 +1,49 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='test'", + "rect": [38, 78, 152, 102], + "reason": "forced by layout" + }, + { + "object": "LayoutText #text", + "rect": [39, 79, 146, 99], + "reason": "layoutObject removal" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV id='test'", + "reason": "forced by layout" + }, + { + "object": "RootInlineBox", + "reason": "forced by layout" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutBR BR", + "reason": "forced by layout" + }, + { + "object": "InlineTextBox '\n'", + "reason": "forced by layout" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/svg/tabgroup-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/svg/tabgroup-expected.txt index 439679f..19b0f8dc1 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/svg/tabgroup-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/invalidation/svg/tabgroup-expected.txt
@@ -986,6 +986,42 @@ "reason": "layoutObject removal" }, { + "object": "LayoutSVGPath path", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGPath path id='tabgroupTriangle__0'", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGInlineText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGTSpan tspan", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGInlineText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGTSpan tspan", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGText text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGContainer g id='tabgroupTriangle__0_content'", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGContainer g", + "reason": "layoutObject removal" + }, + { "object": "LayoutSVGContainer g id='tabgroupRect'", "reason": "became visible" },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-compositing-descendant-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-compositing-descendant-expected.png index b8ab72c0..d90e5e4 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-compositing-descendant-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-compositing-descendant-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-ancestor-update-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-ancestor-update-expected.png index acf834c0..9f698bd 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-ancestor-update-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-ancestor-update-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/threaded/compositing/visibility/visibility-simple-video-layer-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/threaded/compositing/visibility/visibility-simple-video-layer-expected.png index 0358adb..13255e5 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/threaded/compositing/visibility/visibility-simple-video-layer-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/threaded/compositing/visibility/visibility-simple-video-layer-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/media/track/track-cue-rendering-vertical-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/media/track/track-cue-rendering-vertical-expected.png index 511fb3f..036197b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/media/track/track-cue-rendering-vertical-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/media/track/track-cue-rendering-vertical-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt index 290e2274..5c4eb76 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -43,9 +43,9 @@ "drawsContent": true, "paintInvalidations": [ { - "object": "LayoutText #text", - "rect": [60, -1, 3, 15], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [61, 0, 1, 13], + "reason": "caret" } ] }, @@ -62,12 +62,12 @@ ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutTextControl INPUT id='root'", "reason": "subtree" + }, + { + "object": "Caret", + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt new file mode 100644 index 0000000..5c4eb76 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -0,0 +1,74 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true + }, + { + "name": "LayoutTextControl INPUT id='root'", + "position": [5, 5], + "bounds": [47, 25], + "drawsContent": true, + "backgroundColor": "#FFFFFF", + "paintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='root'", + "rect": [0, 0, 47, 25], + "reason": "subtree" + }, + { + "object": "LayoutTextControl INPUT id='root'", + "rect": [0, 0, 41, 19], + "reason": "full" + } + ] + }, + { + "name": "LayoutBlockFlow DIV id='inner-editor'", + "position": [6, 6], + "bounds": [35, 13], + "shouldFlattenTransform": false, + "drawsContent": true + }, + { + "name": "Scrolling Layer", + "bounds": [35, 13], + "shouldFlattenTransform": false + }, + { + "name": "Scrolling Contents Layer", + "bounds": [63, 13], + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [61, 0, 1, 13], + "reason": "caret" + } + ] + }, + { + "name": "Overflow Controls Host Layer", + "bounds": [35, 13] + }, + { + "name": "Horizontal Scrollbar Layer", + "position": [0, 13], + "bounds": [35, 0], + "drawsContent": true + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='root'", + "reason": "subtree" + }, + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/media/track/track-cue-rendering-vertical-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/media/track/track-cue-rendering-vertical-expected.png index 8821d6e..4a783c9 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/media/track/track-cue-rendering-vertical-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/media/track/track-cue-rendering-vertical-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt index c68fb98..41e6eca 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt
@@ -7,14 +7,14 @@ "drawsContent": true, "paintInvalidations": [ { - "object": "LayoutText #text", - "rect": [406, 11, 4, 13], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [407, 11, 2, 13], + "reason": "caret" }, { - "object": "LayoutText #text", - "rect": [403, 11, 4, 13], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [404, 11, 2, 13], + "reason": "caret" } ] } @@ -22,11 +22,7 @@ "objectPaintInvalidations": [ { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt index 0fda20b9..46940c2e 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -43,9 +43,9 @@ "drawsContent": true, "paintInvalidations": [ { - "object": "LayoutText #text", - "rect": [65, -1, 3, 15], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [66, 0, 1, 13], + "reason": "caret" } ] }, @@ -62,12 +62,12 @@ ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutTextControl INPUT id='root'", "reason": "subtree" + }, + { + "object": "Caret", + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt index ba7231b..3f18e774 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
@@ -32,31 +32,12 @@ "object": "LayoutText #text", "rect": [6, 6, 42, 13], "reason": "subtree" - }, - { - "object": "LayoutText #text", - "rect": [45, 6, 3, 13], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [45, 6, 3, 13], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [45, 6, 3, 13], - "reason": "invalidate paint rectangle" } ] } ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutTextControl INPUT id='root'", "reason": "subtree" }, @@ -74,11 +55,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/textarea-caret-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/textarea-caret-expected.txt index c6532f6..4c17e86 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/textarea-caret-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/textarea-caret-expected.txt
@@ -35,31 +35,12 @@ "object": "LayoutTextControl TEXTAREA id='editor'", "rect": [153, 9, 15, 15], "reason": "scroll" - }, - { - "object": "LayoutText #text", - "rect": [151, 10, 2, 14], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [151, 10, 2, 14], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [151, 10, 2, 14], - "reason": "invalidate paint rectangle" } ] } ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutTextControl TEXTAREA id='editor'", "reason": "subtree" }, @@ -89,11 +70,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt new file mode 100644 index 0000000..41e6eca --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt
@@ -0,0 +1,29 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [407, 11, 2, 13], + "reason": "caret" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [404, 11, 2, 13], + "reason": "caret" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt new file mode 100644 index 0000000..46940c2e --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -0,0 +1,74 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true + }, + { + "name": "LayoutTextControl INPUT id='root'", + "position": [5, 5], + "bounds": [54, 25], + "drawsContent": true, + "backgroundColor": "#FFFFFF", + "paintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='root'", + "rect": [0, 0, 54, 25], + "reason": "subtree" + }, + { + "object": "LayoutTextControl INPUT id='root'", + "rect": [0, 0, 48, 19], + "reason": "full" + } + ] + }, + { + "name": "LayoutBlockFlow DIV id='inner-editor'", + "position": [6, 6], + "bounds": [42, 13], + "shouldFlattenTransform": false, + "drawsContent": true + }, + { + "name": "Scrolling Layer", + "bounds": [42, 13], + "shouldFlattenTransform": false + }, + { + "name": "Scrolling Contents Layer", + "bounds": [68, 13], + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [66, 0, 1, 13], + "reason": "caret" + } + ] + }, + { + "name": "Overflow Controls Host Layer", + "bounds": [42, 13] + }, + { + "name": "Horizontal Scrollbar Layer", + "position": [0, 13], + "bounds": [42, 0], + "drawsContent": true + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='root'", + "reason": "subtree" + }, + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt new file mode 100644 index 0000000..3f18e774 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
@@ -0,0 +1,70 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true + }, + { + "name": "LayoutTextControl INPUT id='root'", + "position": [5, 5], + "bounds": [54, 25], + "drawsContent": true, + "backgroundColor": "#FFFFFF", + "paintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='root'", + "rect": [0, 0, 54, 25], + "reason": "subtree" + }, + { + "object": "LayoutTextControl INPUT id='root'", + "rect": [0, 0, 48, 19], + "reason": "full" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [6, 6, 42, 13], + "reason": "subtree" + }, + { + "object": "LayoutText #text", + "rect": [6, 6, 42, 13], + "reason": "subtree" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='root'", + "reason": "subtree" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "reason": "subtree" + }, + { + "object": "RootInlineBox", + "reason": "subtree" + }, + { + "object": "HorizontalScrollbar", + "reason": "scroll" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutText #text", + "reason": "subtree" + }, + { + "object": "InlineTextBox 'test test test'", + "reason": "subtree" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/invalidation/textarea-caret-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/invalidation/textarea-caret-expected.txt new file mode 100644 index 0000000..4c17e86 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/invalidation/textarea-caret-expected.txt
@@ -0,0 +1,85 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutTextControl TEXTAREA id='editor'", + "rect": [5, 5, 167, 38], + "reason": "subtree" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [11, 11, 155, 13], + "reason": "subtree" + }, + { + "object": "LayoutTextControl TEXTAREA id='editor'", + "rect": [9, 24, 144, 15], + "reason": "scroll" + }, + { + "object": "LayoutText #text", + "rect": [9, 11, 144, 13], + "reason": "subtree" + }, + { + "object": "LayoutTextControl TEXTAREA id='editor'", + "rect": [153, 24, 15, 15], + "reason": "scroll" + }, + { + "object": "LayoutTextControl TEXTAREA id='editor'", + "rect": [153, 9, 15, 15], + "reason": "scroll" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutTextControl TEXTAREA id='editor'", + "reason": "subtree" + }, + { + "object": "LayoutTextControl TEXTAREA id='editor'", + "reason": "scroll" + }, + { + "object": "HorizontalScrollbar", + "reason": "scroll" + }, + { + "object": "LayoutTextControl TEXTAREA id='editor'", + "reason": "scroll" + }, + { + "object": "VerticalScrollbar", + "reason": "scroll" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "reason": "subtree" + }, + { + "object": "RootInlineBox", + "reason": "subtree" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutText #text", + "reason": "subtree" + }, + { + "object": "InlineTextBox '------------------------------------------------------------'", + "reason": "subtree" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/video-fixed-scrolling-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/video-fixed-scrolling-expected.png index 5859a58..3dead93 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/video-fixed-scrolling-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/video-fixed-scrolling-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/video-opacity-overlay-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/video-opacity-overlay-expected.png index 3dab51bc..ec4144d 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/video-opacity-overlay-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/video-opacity-overlay-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/layers-inside-overflow-scroll-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/layers-inside-overflow-scroll-expected.png index d8665b9..88ce8a5 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/compositing/layers-inside-overflow-scroll-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/layers-inside-overflow-scroll-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/overflow-compositing-descendant-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/overflow-compositing-descendant-expected.png index 8b758b8..5dcfcced 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/overflow-compositing-descendant-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/overflow-compositing-descendant-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/scroll-ancestor-update-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/scroll-ancestor-update-expected.png index 97472d4..58f1d2e 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/scroll-ancestor-update-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/scroll-ancestor-update-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/reflections/load-video-in-reflection-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/reflections/load-video-in-reflection-expected.png index 737c0c7..6287493 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/compositing/reflections/load-video-in-reflection-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/reflections/load-video-in-reflection-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/self-painting-layers-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/self-painting-layers-expected.png index 714a686..f7a37b07 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/compositing/self-painting-layers-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/self-painting-layers-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/video-frame-size-change-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/video-frame-size-change-expected.png index 94917a6..b53221b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/compositing/video-frame-size-change-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/video-frame-size-change-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/video/video-reflection-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/video/video-reflection-expected.png new file mode 100644 index 0000000..635d07ac --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/video/video-reflection-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/visibility/visibility-simple-video-layer-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/visibility/visibility-simple-video-layer-expected.png index e8ed00f..f73826d2 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/compositing/visibility/visibility-simple-video-layer-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/visibility/visibility-simple-video-layer-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-expected.png index 9a0d45f7..9ebc121d 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-ratio-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-ratio-expected.png index e99a9dc..6066275 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-ratio-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-ratio-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-shadow-expected.png index ab5b41f6..7ac74a8 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-shadow-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-shadow-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-video-seek-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-video-seek-expected.png deleted file mode 100644 index f60f9a7f..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-video-seek-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-video-seek-filter-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-video-seek-filter-expected.png index 7ea462b..2b5e0b3 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-video-seek-filter-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-video-seek-filter-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-video-seek-object-fit-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-video-seek-object-fit-expected.png new file mode 100644 index 0000000..c4a1a2f --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-video-seek-object-fit-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/track/track-cue-rendering-horizontal-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/track/track-cue-rendering-horizontal-expected.png index 4d4cb940..12a7f5b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/track/track-cue-rendering-horizontal-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/track/track-cue-rendering-horizontal-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/track/track-cue-rendering-vertical-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/track/track-cue-rendering-vertical-expected.png index 6512c5d3..3167590f5 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/track/track-cue-rendering-vertical-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/track/track-cue-rendering-vertical-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-aspect-ratio-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/video-aspect-ratio-expected.png index 6fb71684..1a784a2 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-aspect-ratio-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-aspect-ratio-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-canvas-alpha-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/video-canvas-alpha-expected.png index 5d02b16..6af9546 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-canvas-alpha-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-canvas-alpha-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-colorspace-yuv420-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/video-colorspace-yuv420-expected.png index 32da89da..ed67832 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-colorspace-yuv420-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-colorspace-yuv420-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-colorspace-yuv422-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/video-colorspace-yuv422-expected.png index ee7d7c76..32891b8 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-colorspace-yuv422-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-colorspace-yuv422-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-layer-crash-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/video-layer-crash-expected.png index 045af76..908effe 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-layer-crash-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-layer-crash-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-overlay-cast-dark-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/video-overlay-cast-dark-rendering-expected.png index a757e8c..b9d3d61 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-overlay-cast-dark-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-overlay-cast-dark-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-overlay-cast-light-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/video-overlay-cast-light-rendering-expected.png index 9793730e..e92135e 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-overlay-cast-light-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-overlay-cast-light-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-remove-insert-repaints-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/video-remove-insert-repaints-expected.png index b12a3ac6..47efc6a 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-remove-insert-repaints-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-remove-insert-repaints-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-replaces-poster-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/video-replaces-poster-expected.png index bd8df39..f473881b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-replaces-poster-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-replaces-poster-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-transformed-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/video-transformed-expected.png index 5142f6d9..d943ac80 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-transformed-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-transformed-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.png index a624ad74..f4549b6b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-expected.png index 722f96d..ac844f4 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/4776765-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/4776765-expected.txt index 6c14222..24d7fa1 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/4776765-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/4776765-expected.txt
@@ -18,37 +18,14 @@ }, { "object": "LayoutBlockFlow DIV id='div'", - "rect": [7, 77, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='div'", - "rect": [7, 77, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='div'", - "rect": [7, 77, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='div'", - "rect": [7, 59, 3, 20], - "reason": "invalidate paint rectangle" + "rect": [8, 60, 1, 18], + "reason": "caret" } ] } ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV", "reason": "border box change" }, @@ -62,11 +39,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutBR BR",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/bugzilla-6473-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/bugzilla-6473-expected.txt index 2095f85..03da1de 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/bugzilla-6473-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/bugzilla-6473-expected.txt
@@ -14,22 +14,22 @@ { "object": "LayoutBlockFlow (relative positioned) P", "rect": [8, 146, 784, 18], - "reason": "bounds change" + "reason": "forced by layout" }, { "object": "LayoutBlockFlow (relative positioned) P", "rect": [8, 130, 784, 18], - "reason": "bounds change" + "reason": "forced by layout" }, { "object": "LayoutText #text", "rect": [8, 146, 70, 18], - "reason": "bounds change" + "reason": "forced by layout" }, { "object": "LayoutText #text", "rect": [8, 130, 70, 18], - "reason": "bounds change" + "reason": "forced by layout" } ] } @@ -41,19 +41,19 @@ }, { "object": "LayoutBlockFlow (relative positioned) P", - "reason": "bounds change" + "reason": "forced by layout" }, { "object": "RootInlineBox", - "reason": "bounds change" + "reason": "forced by layout" }, { "object": "LayoutText #text", - "reason": "bounds change" + "reason": "forced by layout" }, { "object": "InlineTextBox 'SUCCESS'", - "reason": "bounds change" + "reason": "forced by layout" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-contenteditable-content-after-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-contenteditable-content-after-expected.txt index b99edf5..a229f032 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-contenteditable-content-after-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-contenteditable-content-after-expected.txt
@@ -70,91 +70,12 @@ "object": "LayoutTextFragment (anonymous)", "rect": [8, 44, 8, 18], "reason": "forced by layout" - }, - { - "object": "LayoutText #text", - "rect": [29, 43, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [29, 43, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [29, 43, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [22, 43, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [22, 43, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [22, 43, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [22, 43, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [14, 43, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [14, 43, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [14, 43, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [14, 43, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='editor'", - "rect": [7, 43, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='editor'", - "rect": [7, 43, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='editor'", - "rect": [7, 43, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='editor'", - "rect": [7, 43, 3, 20], - "reason": "invalidate paint rectangle" } ] } ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV id='editor'", "reason": "style change" }, @@ -164,19 +85,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutBlockFlow DIV id='editor'", @@ -188,11 +97,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutText #text", @@ -211,14 +116,6 @@ "reason": "forced by layout" }, { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV id='editor'", "reason": "forced by layout" }, @@ -228,11 +125,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutText #text", @@ -251,14 +144,6 @@ "reason": "forced by layout" }, { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV id='editor'", "reason": "forced by layout" }, @@ -268,11 +153,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt index e9d6a019..cc332d1 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt
@@ -7,14 +7,14 @@ "drawsContent": true, "paintInvalidations": [ { - "object": "LayoutText #text", - "rect": [406, 11, 4, 13], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [407, 11, 2, 13], + "reason": "caret" }, { - "object": "LayoutText #text", - "rect": [404, 11, 4, 13], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [405, 11, 2, 13], + "reason": "caret" } ] } @@ -22,11 +22,7 @@ "objectPaintInvalidations": [ { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-outside-block-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-outside-block-expected.txt index 5032a2b..12a8fe8 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-outside-block-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-outside-block-expected.txt
@@ -7,9 +7,9 @@ "drawsContent": true, "paintInvalidations": [ { - "object": "LayoutText #text", - "rect": [790, 7, 3, 20], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='target'", + "rect": [791, 8, 1, 18], + "reason": "caret" } ] } @@ -17,7 +17,7 @@ "objectPaintInvalidations": [ { "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-subpixel-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-subpixel-expected.txt index 5ea166a..05c1760 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-subpixel-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-subpixel-expected.txt
@@ -15,31 +15,12 @@ "object": "LayoutBlockFlow DIV id='inner-editor'", "rect": [11, 11, 201, 13], "reason": "subtree" - }, - { - "object": "LayoutBlockFlow DIV id='inner-editor'", - "rect": [209, 10, 4, 15], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='inner-editor'", - "rect": [209, 10, 4, 15], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='inner-editor'", - "rect": [209, 10, 4, 15], - "reason": "invalidate paint rectangle" } ] } ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutTextControl INPUT id='target'", "reason": "subtree" }, @@ -49,11 +30,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-composited-scroll-expected.txt index 051f328b..69ee0c96f 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-composited-scroll-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-composited-scroll-expected.txt
@@ -32,21 +32,6 @@ "object": "LayoutBlockFlow DIV id='inner-editor'", "rect": [3, 1003, 200, 13], "reason": "subtree" - }, - { - "object": "LayoutBlockFlow DIV id='inner-editor'", - "rect": [2, 1002, 3, 15], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='inner-editor'", - "rect": [2, 1002, 3, 15], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='inner-editor'", - "rect": [2, 1002, 3, 15], - "reason": "invalidate paint rectangle" } ] }, @@ -69,10 +54,6 @@ ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutTextControl INPUT id='text'", "reason": "subtree" }, @@ -82,11 +63,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-transformation-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-transformation-expected.txt index f266bc7..56b54e8 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-transformation-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-transformation-expected.txt
@@ -7,14 +7,14 @@ "drawsContent": true, "paintInvalidations": [ { - "object": "LayoutText #text", - "rect": [344, 210, 13, 19], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='div'", + "rect": [345, 211, 11, 17], + "reason": "caret" }, { - "object": "LayoutText #text", - "rect": [41, 35, 13, 19], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='div'", + "rect": [42, 36, 11, 17], + "reason": "caret" } ] } @@ -22,11 +22,7 @@ "objectPaintInvalidations": [ { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/delete-into-nested-block-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/delete-into-nested-block-expected.txt index 60e6f62..0512beb 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/delete-into-nested-block-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/delete-into-nested-block-expected.txt
@@ -45,21 +45,6 @@ "object": "LayoutText #text", "rect": [8, 119, 28, 19], "reason": "layoutObject removal" - }, - { - "object": "LayoutText #text", - "rect": [7, 118, 3, 21], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [7, 118, 3, 21], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [7, 118, 3, 21], - "reason": "invalidate paint rectangle" } ] } @@ -106,10 +91,6 @@ "reason": "layoutObject removal" }, { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV id='one'", "reason": "full" }, @@ -119,11 +100,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/inline-outline-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/inline-outline-repaint-expected.txt index 57abbbad..0b4af2de 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/inline-outline-repaint-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/inline-outline-repaint-expected.txt
@@ -20,21 +20,6 @@ "object": "LayoutText #text", "rect": [8, 166, 92, 36], "reason": "full" - }, - { - "object": "LayoutText #text", - "rect": [45, 183, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [45, 183, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [45, 183, 3, 20], - "reason": "invalidate paint rectangle" } ] } @@ -45,10 +30,6 @@ "reason": "layoutObject removal" }, { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV", "reason": "forced by layout" }, @@ -58,11 +39,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutInline SPAN id='test'",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-before-text-node-update-expected.png b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-before-text-node-update-expected.png new file mode 100644 index 0000000..4a30daf --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-before-text-node-update-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-before-text-node-update-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-before-text-node-update-expected.txt new file mode 100644 index 0000000..a353a49 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-before-text-node-update-expected.txt
@@ -0,0 +1,37 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='root' class='editing'", + "rect": [3, 3, 794, 28], + "reason": "full" + }, + { + "object": "LayoutText #text", + "rect": [8, 8, 10, 18], + "reason": "layoutObject removal" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV id='root' class='editing'", + "reason": "full" + }, + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt index 8578323..ab30ad6b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -43,9 +43,9 @@ "drawsContent": true, "paintInvalidations": [ { - "object": "LayoutText #text", - "rect": [64, -1, 3, 15], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [65, 0, 1, 13], + "reason": "caret" } ] }, @@ -62,12 +62,12 @@ ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutTextControl INPUT id='root'", "reason": "subtree" + }, + { + "object": "Caret", + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt index 06dfd1e0..c603627 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
@@ -32,31 +32,12 @@ "object": "LayoutText #text", "rect": [6, 6, 35, 13], "reason": "subtree" - }, - { - "object": "LayoutText #text", - "rect": [38, 6, 3, 13], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [38, 6, 3, 13], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [38, 6, 3, 13], - "reason": "invalidate paint rectangle" } ] } ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutTextControl INPUT id='root'", "reason": "subtree" }, @@ -74,11 +55,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/selection-after-delete-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/selection-after-delete-expected.txt index 866a0f3..f900996 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/selection-after-delete-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/selection-after-delete-expected.txt
@@ -15,21 +15,6 @@ "object": "LayoutText #text", "rect": [39, 75, 123, 108], "reason": "layoutObject removal" - }, - { - "object": "LayoutBlockFlow DIV id='test'", - "rect": [38, 74, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='test'", - "rect": [38, 74, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='test'", - "rect": [38, 74, 3, 20], - "reason": "invalidate paint rectangle" } ] } @@ -40,10 +25,6 @@ "reason": "layoutObject removal" }, { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV id='test'", "reason": "forced by layout" }, @@ -53,11 +34,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutBR BR",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/tabgroup-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/tabgroup-expected.txt index a1ffc87..22e7e04 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/tabgroup-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/tabgroup-expected.txt
@@ -986,6 +986,42 @@ "reason": "layoutObject removal" }, { + "object": "LayoutSVGPath path", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGPath path id='tabgroupTriangle__0'", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGInlineText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGTSpan tspan", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGInlineText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGTSpan tspan", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGText text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGContainer g id='tabgroupTriangle__0_content'", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGContainer g", + "reason": "layoutObject removal" + }, + { "object": "LayoutSVGContainer g id='tabgroupRect'", "reason": "became visible" },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/textarea-caret-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/textarea-caret-expected.txt index 16d5346..989d7ec 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/textarea-caret-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/textarea-caret-expected.txt
@@ -35,31 +35,12 @@ "object": "LayoutTextControl TEXTAREA id='editor'", "rect": [133, 9, 15, 15], "reason": "scroll" - }, - { - "object": "LayoutText #text", - "rect": [131, 10, 2, 14], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [131, 10, 2, 14], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [131, 10, 2, 14], - "reason": "invalidate paint rectangle" } ] } ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutTextControl TEXTAREA id='editor'", "reason": "subtree" }, @@ -89,11 +70,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/4776765-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/4776765-expected.txt new file mode 100644 index 0000000..24d7fa1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/4776765-expected.txt
@@ -0,0 +1,54 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV", + "rect": [3, 37, 794, 64], + "reason": "border box change" + }, + { + "object": "LayoutBlockFlow DIV id='div'", + "rect": [8, 78, 784, 18], + "reason": "layoutObject insertion" + }, + { + "object": "LayoutBlockFlow DIV id='div'", + "rect": [8, 60, 1, 18], + "reason": "caret" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutBlockFlow DIV", + "reason": "border box change" + }, + { + "object": "LayoutBlockFlow DIV id='div'", + "reason": "layoutObject insertion" + }, + { + "object": "RootInlineBox", + "reason": "layoutObject insertion" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutBR BR", + "reason": "layoutObject insertion" + }, + { + "object": "InlineTextBox '\n'", + "reason": "layoutObject insertion" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-contenteditable-content-after-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-contenteditable-content-after-expected.txt new file mode 100644 index 0000000..a229f032 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-contenteditable-content-after-expected.txt
@@ -0,0 +1,176 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='editor'", + "rect": [3, 39, 794, 28], + "reason": "style change" + }, + { + "object": "LayoutBlockFlow DIV id='editor'", + "rect": [3, 39, 794, 28], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow DIV id='editor'", + "rect": [3, 39, 794, 28], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow DIV id='editor'", + "rect": [3, 39, 794, 28], + "reason": "forced by layout" + }, + { + "object": "LayoutText #text", + "rect": [8, 44, 23, 18], + "reason": "full" + }, + { + "object": "LayoutText #text", + "rect": [8, 44, 16, 18], + "reason": "full" + }, + { + "object": "LayoutTextFragment (anonymous)", + "rect": [30, 44, 9, 18], + "reason": "forced by layout" + }, + { + "object": "LayoutTextFragment (anonymous)", + "rect": [23, 44, 9, 18], + "reason": "forced by layout" + }, + { + "object": "LayoutTextFragment (anonymous)", + "rect": [23, 44, 9, 18], + "reason": "forced by layout" + }, + { + "object": "LayoutTextFragment (anonymous)", + "rect": [15, 44, 9, 18], + "reason": "forced by layout" + }, + { + "object": "LayoutTextFragment (anonymous)", + "rect": [15, 44, 9, 18], + "reason": "forced by layout" + }, + { + "object": "LayoutText #text", + "rect": [8, 44, 8, 18], + "reason": "layoutObject insertion" + }, + { + "object": "LayoutTextFragment (anonymous)", + "rect": [8, 44, 8, 18], + "reason": "forced by layout" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='editor'", + "reason": "style change" + }, + { + "object": "RootInlineBox", + "reason": "style change" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutBlockFlow DIV id='editor'", + "reason": "forced by layout" + }, + { + "object": "RootInlineBox", + "reason": "forced by layout" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutText #text", + "reason": "layoutObject insertion" + }, + { + "object": "InlineTextBox 'a'", + "reason": "layoutObject insertion" + }, + { + "object": "LayoutTextFragment (anonymous)", + "reason": "forced by layout" + }, + { + "object": "InlineTextBox 'x'", + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow DIV id='editor'", + "reason": "forced by layout" + }, + { + "object": "RootInlineBox", + "reason": "forced by layout" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutText #text", + "reason": "full" + }, + { + "object": "InlineTextBox 'ab'", + "reason": "full" + }, + { + "object": "LayoutTextFragment (anonymous)", + "reason": "forced by layout" + }, + { + "object": "InlineTextBox 'x'", + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow DIV id='editor'", + "reason": "forced by layout" + }, + { + "object": "RootInlineBox", + "reason": "forced by layout" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutText #text", + "reason": "full" + }, + { + "object": "InlineTextBox 'abc'", + "reason": "full" + }, + { + "object": "LayoutTextFragment (anonymous)", + "reason": "forced by layout" + }, + { + "object": "InlineTextBox 'x'", + "reason": "forced by layout" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt new file mode 100644 index 0000000..cc332d1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt
@@ -0,0 +1,29 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [407, 11, 2, 13], + "reason": "caret" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [405, 11, 2, 13], + "reason": "caret" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-outside-block-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-outside-block-expected.txt new file mode 100644 index 0000000..12a8fe8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-outside-block-expected.txt
@@ -0,0 +1,24 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='target'", + "rect": [791, 8, 1, 18], + "reason": "caret" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-subpixel-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-subpixel-expected.txt new file mode 100644 index 0000000..05c1760 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-subpixel-expected.txt
@@ -0,0 +1,37 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='target'", + "rect": [8, 8, 225, 19], + "reason": "subtree" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [11, 11, 201, 13], + "reason": "subtree" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='target'", + "reason": "subtree" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "reason": "subtree" + }, + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll-expected.txt new file mode 100644 index 0000000..69ee0c96f --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll-expected.txt
@@ -0,0 +1,70 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true + }, + { + "name": "LayoutBlockFlow DIV id='scroller'", + "position": [8, 44], + "bounds": [100, 100], + "shouldFlattenTransform": false, + "drawsContent": true + }, + { + "name": "Scrolling Layer", + "bounds": [100, 100], + "shouldFlattenTransform": false + }, + { + "name": "Scrolling Contents Layer", + "bounds": [205, 1019], + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='text'", + "rect": [-3, 997, 211, 25], + "reason": "subtree" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [3, 1003, 200, 13], + "reason": "subtree" + } + ] + }, + { + "name": "Overflow Controls Host Layer", + "bounds": [100, 100] + }, + { + "name": "Horizontal Scrollbar Layer", + "position": [0, 100], + "bounds": [100, 0], + "drawsContent": true + }, + { + "name": "Vertical Scrollbar Layer", + "position": [100, 0], + "bounds": [0, 100], + "drawsContent": true + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='text'", + "reason": "subtree" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "reason": "subtree" + }, + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-with-transformation-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-with-transformation-expected.txt new file mode 100644 index 0000000..56b54e8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/caret-with-transformation-expected.txt
@@ -0,0 +1,29 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='div'", + "rect": [345, 211, 11, 17], + "reason": "caret" + }, + { + "object": "LayoutBlockFlow DIV id='div'", + "rect": [42, 36, 11, 17], + "reason": "caret" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/delete-into-nested-block-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/delete-into-nested-block-expected.txt new file mode 100644 index 0000000..0512beb --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/delete-into-nested-block-expected.txt
@@ -0,0 +1,115 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='two'", + "rect": [8, 137, 784, 37], + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV", + "rect": [8, 155, 784, 19], + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV", + "rect": [8, 137, 784, 19], + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV id='one'", + "rect": [8, 119, 784, 19], + "reason": "full" + }, + { + "object": "LayoutText #text", + "rect": [8, 155, 32, 19], + "reason": "layoutObject removal" + }, + { + "object": "LayoutText #text", + "rect": [8, 119, 32, 19], + "reason": "layoutObject insertion" + }, + { + "object": "LayoutText #text", + "rect": [8, 137, 28, 19], + "reason": "layoutObject removal" + }, + { + "object": "LayoutText #text", + "rect": [8, 119, 28, 19], + "reason": "layoutObject removal" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV", + "reason": "layoutObject removal" + }, + { + "object": "LayoutText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBR BR", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV id='two'", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBR BR", + "reason": "layoutObject removal" + }, + { + "object": "LayoutText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutInline SPAN", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV id='one'", + "reason": "full" + }, + { + "object": "RootInlineBox", + "reason": "full" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutText #text", + "reason": "layoutObject insertion" + }, + { + "object": "InlineTextBox 'three'", + "reason": "layoutObject insertion" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/inline-outline-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/inline-outline-repaint-expected.txt new file mode 100644 index 0000000..0b4af2de --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/inline-outline-repaint-expected.txt
@@ -0,0 +1,74 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV", + "rect": [8, 166, 100, 36], + "reason": "forced by layout" + }, + { + "object": "LayoutInline SPAN id='test'", + "rect": [5, 163, 98, 42], + "reason": "forced by layout" + }, + { + "object": "LayoutText #text", + "rect": [8, 166, 92, 36], + "reason": "full" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV", + "reason": "forced by layout" + }, + { + "object": "RootInlineBox", + "reason": "forced by layout" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutInline SPAN id='test'", + "reason": "forced by layout" + }, + { + "object": "InlineFlowBox", + "reason": "forced by layout" + }, + { + "object": "InlineFlowBox", + "reason": "forced by layout" + }, + { + "object": "LayoutText #text", + "reason": "full" + }, + { + "object": "InlineTextBox 'Lorem ipsum'", + "reason": "full" + }, + { + "object": "InlineTextBox ' '", + "reason": "full" + }, + { + "object": "InlineTextBox 'dolor\u00A0'", + "reason": "full" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-before-text-node-update-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-before-text-node-update-expected.png new file mode 100644 index 0000000..4a30daf --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-before-text-node-update-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-before-text-node-update-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-before-text-node-update-expected.txt new file mode 100644 index 0000000..a353a49 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-before-text-node-update-expected.txt
@@ -0,0 +1,37 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='root' class='editing'", + "rect": [3, 3, 794, 28], + "reason": "full" + }, + { + "object": "LayoutText #text", + "rect": [8, 8, 10, 18], + "reason": "layoutObject removal" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV id='root' class='editing'", + "reason": "full" + }, + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt new file mode 100644 index 0000000..ab30ad6b --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -0,0 +1,74 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true + }, + { + "name": "LayoutTextControl INPUT id='root'", + "position": [5, 5], + "bounds": [47, 25], + "drawsContent": true, + "backgroundColor": "#FFFFFF", + "paintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='root'", + "rect": [0, 0, 47, 25], + "reason": "subtree" + }, + { + "object": "LayoutTextControl INPUT id='root'", + "rect": [0, 0, 41, 19], + "reason": "full" + } + ] + }, + { + "name": "LayoutBlockFlow DIV id='inner-editor'", + "position": [6, 6], + "bounds": [35, 13], + "shouldFlattenTransform": false, + "drawsContent": true + }, + { + "name": "Scrolling Layer", + "bounds": [35, 13], + "shouldFlattenTransform": false + }, + { + "name": "Scrolling Contents Layer", + "bounds": [67, 13], + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [65, 0, 1, 13], + "reason": "caret" + } + ] + }, + { + "name": "Overflow Controls Host Layer", + "bounds": [35, 13] + }, + { + "name": "Horizontal Scrollbar Layer", + "position": [0, 13], + "bounds": [35, 0], + "drawsContent": true + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='root'", + "reason": "subtree" + }, + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt new file mode 100644 index 0000000..c603627 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
@@ -0,0 +1,70 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true + }, + { + "name": "LayoutTextControl INPUT id='root'", + "position": [5, 5], + "bounds": [47, 25], + "drawsContent": true, + "backgroundColor": "#FFFFFF", + "paintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='root'", + "rect": [0, 0, 47, 25], + "reason": "subtree" + }, + { + "object": "LayoutTextControl INPUT id='root'", + "rect": [0, 0, 41, 19], + "reason": "full" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [6, 6, 35, 13], + "reason": "subtree" + }, + { + "object": "LayoutText #text", + "rect": [6, 6, 35, 13], + "reason": "subtree" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='root'", + "reason": "subtree" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "reason": "subtree" + }, + { + "object": "RootInlineBox", + "reason": "subtree" + }, + { + "object": "HorizontalScrollbar", + "reason": "scroll" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutText #text", + "reason": "subtree" + }, + { + "object": "InlineTextBox 'test test test'", + "reason": "subtree" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/selection-after-delete-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/selection-after-delete-expected.txt new file mode 100644 index 0000000..f900996 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/selection-after-delete-expected.txt
@@ -0,0 +1,49 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='test'", + "rect": [38, 74, 152, 110], + "reason": "forced by layout" + }, + { + "object": "LayoutText #text", + "rect": [39, 75, 123, 108], + "reason": "layoutObject removal" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV id='test'", + "reason": "forced by layout" + }, + { + "object": "RootInlineBox", + "reason": "forced by layout" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutBR BR", + "reason": "forced by layout" + }, + { + "object": "InlineTextBox '\n'", + "reason": "forced by layout" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/svg/tabgroup-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/svg/tabgroup-expected.txt index eaa97c6..4b082a1 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/svg/tabgroup-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/svg/tabgroup-expected.txt
@@ -986,6 +986,42 @@ "reason": "layoutObject removal" }, { + "object": "LayoutSVGPath path", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGPath path id='tabgroupTriangle__0'", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGInlineText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGTSpan tspan", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGInlineText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGTSpan tspan", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGText text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGContainer g id='tabgroupTriangle__0_content'", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGContainer g", + "reason": "layoutObject removal" + }, + { "object": "LayoutSVGContainer g id='tabgroupRect'", "reason": "became visible" },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/textarea-caret-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/textarea-caret-expected.txt new file mode 100644 index 0000000..989d7ec --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/invalidation/textarea-caret-expected.txt
@@ -0,0 +1,85 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutTextControl TEXTAREA id='editor'", + "rect": [5, 5, 147, 38], + "reason": "subtree" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [11, 11, 135, 13], + "reason": "subtree" + }, + { + "object": "LayoutTextControl TEXTAREA id='editor'", + "rect": [9, 24, 124, 15], + "reason": "scroll" + }, + { + "object": "LayoutText #text", + "rect": [9, 11, 124, 13], + "reason": "subtree" + }, + { + "object": "LayoutTextControl TEXTAREA id='editor'", + "rect": [133, 24, 15, 15], + "reason": "scroll" + }, + { + "object": "LayoutTextControl TEXTAREA id='editor'", + "rect": [133, 9, 15, 15], + "reason": "scroll" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutTextControl TEXTAREA id='editor'", + "reason": "subtree" + }, + { + "object": "LayoutTextControl TEXTAREA id='editor'", + "reason": "scroll" + }, + { + "object": "HorizontalScrollbar", + "reason": "scroll" + }, + { + "object": "LayoutTextControl TEXTAREA id='editor'", + "reason": "scroll" + }, + { + "object": "VerticalScrollbar", + "reason": "scroll" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "reason": "subtree" + }, + { + "object": "RootInlineBox", + "reason": "subtree" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutText #text", + "reason": "subtree" + }, + { + "object": "InlineTextBox '------------------------------------------------------------'", + "reason": "subtree" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-compositing-descendant-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-compositing-descendant-expected.png index 8b758b8..5dcfcced 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-compositing-descendant-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-compositing-descendant-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-ancestor-update-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-ancestor-update-expected.png index 97472d4..58f1d2e 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-ancestor-update-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-ancestor-update-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt index d6b67ab..0ae8359 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -3116,6 +3116,7 @@ getter boundingClientRect getter intersectionRatio getter intersectionRect + getter isIntersecting getter rootBounds getter target getter time
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/threaded/compositing/visibility/visibility-simple-video-layer-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/threaded/compositing/visibility/visibility-simple-video-layer-expected.png index e8ed00f..f73826d2 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/threaded/compositing/visibility/visibility-simple-video-layer-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/threaded/compositing/visibility/visibility-simple-video-layer-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/video-fixed-scrolling-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/video-fixed-scrolling-expected.png index 49abdc4b..085fbd8 100644 --- a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/video-fixed-scrolling-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/video-fixed-scrolling-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/video-opacity-overlay-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/video-opacity-overlay-expected.png index a924ef5..b6f5527 100644 --- a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/video-opacity-overlay-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/video-opacity-overlay-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/layers-inside-overflow-scroll-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/layers-inside-overflow-scroll-expected.png index fb99b3e..81abb48 100644 --- a/third_party/WebKit/LayoutTests/platform/win/compositing/layers-inside-overflow-scroll-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/compositing/layers-inside-overflow-scroll-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/overflow-compositing-descendant-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/overflow-compositing-descendant-expected.png index 4cc4008..e3951651 100644 --- a/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/overflow-compositing-descendant-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/overflow-compositing-descendant-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/scroll-ancestor-update-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/scroll-ancestor-update-expected.png index 63c36eb..5c9c6699 100644 --- a/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/scroll-ancestor-update-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/scroll-ancestor-update-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/reflections/load-video-in-reflection-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/reflections/load-video-in-reflection-expected.png index f9e0ad4..d996cfd0 100644 --- a/third_party/WebKit/LayoutTests/platform/win/compositing/reflections/load-video-in-reflection-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/compositing/reflections/load-video-in-reflection-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/self-painting-layers-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/self-painting-layers-expected.png index 8461050..f0a72cb 100644 --- a/third_party/WebKit/LayoutTests/platform/win/compositing/self-painting-layers-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/compositing/self-painting-layers-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/video-frame-size-change-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/video-frame-size-change-expected.png index 2006304..b7e1211 100644 --- a/third_party/WebKit/LayoutTests/platform/win/compositing/video-frame-size-change-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/compositing/video-frame-size-change-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/video/video-reflection-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/video/video-reflection-expected.png new file mode 100644 index 0000000..3928dfe --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/compositing/video/video-reflection-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/visibility/visibility-simple-video-layer-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/visibility/visibility-simple-video-layer-expected.png index 34146f9..5490ee0 100644 --- a/third_party/WebKit/LayoutTests/platform/win/compositing/visibility/visibility-simple-video-layer-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/compositing/visibility/visibility-simple-video-layer-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-expected.png index 17b4e4e3..2c2391f 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-ratio-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-ratio-expected.png index 08ef120..76c6fd8 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-ratio-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-ratio-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-shadow-expected.png index 56d9f40..1882713 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-shadow-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-shadow-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/color-profile-video-seek-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/color-profile-video-seek-expected.png deleted file mode 100644 index db562b2..0000000 --- a/third_party/WebKit/LayoutTests/platform/win/media/color-profile-video-seek-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/color-profile-video-seek-filter-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/color-profile-video-seek-filter-expected.png index 976186d..5fcb88be 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/color-profile-video-seek-filter-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/color-profile-video-seek-filter-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/color-profile-video-seek-object-fit-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/color-profile-video-seek-object-fit-expected.png new file mode 100644 index 0000000..226f7ca9 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/media/color-profile-video-seek-object-fit-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/track/track-cue-rendering-horizontal-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/track/track-cue-rendering-horizontal-expected.png index ee4fd8fc..ae97747 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/track/track-cue-rendering-horizontal-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/track/track-cue-rendering-horizontal-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/track/track-cue-rendering-vertical-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/track/track-cue-rendering-vertical-expected.png index b6e4369..5b38b29 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/track/track-cue-rendering-vertical-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/track/track-cue-rendering-vertical-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-aspect-ratio-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/video-aspect-ratio-expected.png index f6d4533..155f37b 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-aspect-ratio-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-aspect-ratio-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-canvas-alpha-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/video-canvas-alpha-expected.png index 885587fb..2810de4 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-canvas-alpha-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-canvas-alpha-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-colorspace-yuv420-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/video-colorspace-yuv420-expected.png index 7290bad..54931708 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-colorspace-yuv420-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-colorspace-yuv420-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-colorspace-yuv422-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/video-colorspace-yuv422-expected.png index 1148578..9831d31 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-colorspace-yuv422-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-colorspace-yuv422-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-overlay-cast-dark-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/video-overlay-cast-dark-rendering-expected.png index 1fe5973..97ae9fa6 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-overlay-cast-dark-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-overlay-cast-dark-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-overlay-cast-light-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/video-overlay-cast-light-rendering-expected.png index 3cd7a2f..8d1a169 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-overlay-cast-light-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-overlay-cast-light-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-remove-insert-repaints-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/video-remove-insert-repaints-expected.png index 133416c5..4ae9de3 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-remove-insert-repaints-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-remove-insert-repaints-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-replaces-poster-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/video-replaces-poster-expected.png index b920eb24..058ab2c7 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-replaces-poster-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-replaces-poster-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.png index bc8187f..e04ee352 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-expected.png index 40b6630..37afe2f 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/4776765-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/4776765-expected.txt index a7965f3..782dcd5 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/4776765-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/4776765-expected.txt
@@ -18,37 +18,14 @@ }, { "object": "LayoutBlockFlow DIV id='div'", - "rect": [7, 77, 3, 19], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='div'", - "rect": [7, 77, 3, 19], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='div'", - "rect": [7, 77, 3, 19], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='div'", - "rect": [7, 59, 3, 19], - "reason": "invalidate paint rectangle" + "rect": [8, 60, 1, 17], + "reason": "caret" } ] } ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV", "reason": "border box change" }, @@ -62,11 +39,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutBR BR",
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/bugzilla-6473-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/bugzilla-6473-expected.txt index 782e78e..6ff2b0b 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/bugzilla-6473-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/bugzilla-6473-expected.txt
@@ -14,22 +14,22 @@ { "object": "LayoutBlockFlow (relative positioned) P", "rect": [8, 146, 784, 18], - "reason": "bounds change" + "reason": "forced by layout" }, { "object": "LayoutBlockFlow (relative positioned) P", "rect": [8, 130, 784, 18], - "reason": "bounds change" + "reason": "forced by layout" }, { "object": "LayoutText #text", "rect": [8, 146, 70, 17], - "reason": "bounds change" + "reason": "forced by layout" }, { "object": "LayoutText #text", "rect": [8, 130, 70, 17], - "reason": "bounds change" + "reason": "forced by layout" } ] } @@ -41,19 +41,19 @@ }, { "object": "LayoutBlockFlow (relative positioned) P", - "reason": "bounds change" + "reason": "forced by layout" }, { "object": "RootInlineBox", - "reason": "bounds change" + "reason": "forced by layout" }, { "object": "LayoutText #text", - "reason": "bounds change" + "reason": "forced by layout" }, { "object": "InlineTextBox 'SUCCESS'", - "reason": "bounds change" + "reason": "forced by layout" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-contenteditable-content-after-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-contenteditable-content-after-expected.txt index 82c392c4..60739a63 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-contenteditable-content-after-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-contenteditable-content-after-expected.txt
@@ -70,91 +70,12 @@ "object": "LayoutTextFragment (anonymous)", "rect": [8, 44, 8, 17], "reason": "forced by layout" - }, - { - "object": "LayoutBlockFlow DIV id='editor'", - "rect": [7, 43, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='editor'", - "rect": [7, 43, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='editor'", - "rect": [7, 43, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='editor'", - "rect": [7, 43, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [29, 43, 3, 19], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [29, 43, 3, 19], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [29, 43, 3, 19], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [22, 43, 3, 19], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [22, 43, 3, 19], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [22, 43, 3, 19], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [22, 43, 3, 19], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [14, 43, 3, 19], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [14, 43, 3, 19], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [14, 43, 3, 19], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [14, 43, 3, 19], - "reason": "invalidate paint rectangle" } ] } ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV id='editor'", "reason": "style change" }, @@ -164,19 +85,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutBlockFlow DIV id='editor'", @@ -188,11 +97,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutText #text", @@ -211,14 +116,6 @@ "reason": "forced by layout" }, { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV id='editor'", "reason": "forced by layout" }, @@ -228,11 +125,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutText #text", @@ -251,14 +144,6 @@ "reason": "forced by layout" }, { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV id='editor'", "reason": "forced by layout" }, @@ -268,11 +153,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt index 637fd24..a86a15a 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt
@@ -7,14 +7,14 @@ "drawsContent": true, "paintInvalidations": [ { - "object": "LayoutText #text", - "rect": [405, 11, 4, 16], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [406, 11, 2, 16], + "reason": "caret" }, { - "object": "LayoutText #text", - "rect": [402, 11, 4, 16], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [403, 11, 2, 16], + "reason": "caret" } ] } @@ -22,11 +22,7 @@ "objectPaintInvalidations": [ { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-outside-block-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-outside-block-expected.txt index d1c76ca..67cae10c 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-outside-block-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-outside-block-expected.txt
@@ -7,9 +7,9 @@ "drawsContent": true, "paintInvalidations": [ { - "object": "LayoutText #text", - "rect": [790, 7, 3, 19], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='target'", + "rect": [791, 8, 1, 17], + "reason": "caret" } ] } @@ -17,7 +17,7 @@ "objectPaintInvalidations": [ { "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-subpixel-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-subpixel-expected.txt index 6c6a94e..ea861c1f 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-subpixel-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-subpixel-expected.txt
@@ -15,31 +15,12 @@ "object": "LayoutBlockFlow DIV id='inner-editor'", "rect": [10, 11, 201, 16], "reason": "subtree" - }, - { - "object": "LayoutBlockFlow DIV id='inner-editor'", - "rect": [208, 10, 4, 18], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='inner-editor'", - "rect": [208, 10, 4, 18], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='inner-editor'", - "rect": [208, 10, 4, 18], - "reason": "invalidate paint rectangle" } ] } ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutTextControl INPUT id='target'", "reason": "subtree" }, @@ -49,11 +30,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-composited-scroll-expected.txt index 9d43c33..1795923f 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-composited-scroll-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-composited-scroll-expected.txt
@@ -32,21 +32,6 @@ "object": "LayoutBlockFlow DIV id='inner-editor'", "rect": [3, 1003, 200, 16], "reason": "subtree" - }, - { - "object": "LayoutBlockFlow DIV id='inner-editor'", - "rect": [2, 1002, 3, 18], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='inner-editor'", - "rect": [2, 1002, 3, 18], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='inner-editor'", - "rect": [2, 1002, 3, 18], - "reason": "invalidate paint rectangle" } ] }, @@ -69,10 +54,6 @@ ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutTextControl INPUT id='text'", "reason": "subtree" }, @@ -82,11 +63,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-transformation-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-transformation-expected.txt index 589fed96..052f1600 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-transformation-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-transformation-expected.txt
@@ -7,14 +7,14 @@ "drawsContent": true, "paintInvalidations": [ { - "object": "LayoutText #text", - "rect": [345, 210, 13, 19], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='div'", + "rect": [347, 211, 10, 17], + "reason": "caret" }, { - "object": "LayoutText #text", - "rect": [41, 35, 13, 18], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='div'", + "rect": [43, 36, 10, 16], + "reason": "caret" } ] } @@ -22,11 +22,7 @@ "objectPaintInvalidations": [ { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/delete-into-nested-block-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/delete-into-nested-block-expected.txt index 63c5497..5ae8fde 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/delete-into-nested-block-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/delete-into-nested-block-expected.txt
@@ -45,21 +45,6 @@ "object": "LayoutText #text", "rect": [8, 119, 28, 18], "reason": "layoutObject removal" - }, - { - "object": "LayoutText #text", - "rect": [7, 118, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [7, 118, 3, 20], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [7, 118, 3, 20], - "reason": "invalidate paint rectangle" } ] } @@ -106,10 +91,6 @@ "reason": "layoutObject removal" }, { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV id='one'", "reason": "full" }, @@ -119,11 +100,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/inline-outline-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/inline-outline-repaint-expected.txt index c53a139..8debaed 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/inline-outline-repaint-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/inline-outline-repaint-expected.txt
@@ -20,21 +20,6 @@ "object": "LayoutText #text", "rect": [8, 166, 92, 35], "reason": "full" - }, - { - "object": "LayoutText #text", - "rect": [45, 183, 3, 19], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [45, 183, 3, 19], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [45, 183, 3, 19], - "reason": "invalidate paint rectangle" } ] } @@ -45,10 +30,6 @@ "reason": "layoutObject removal" }, { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV", "reason": "forced by layout" }, @@ -58,11 +39,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutInline SPAN id='test'",
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt index 13f9dd1..233f3e5d 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -43,9 +43,9 @@ "drawsContent": true, "paintInvalidations": [ { - "object": "LayoutText #text", - "rect": [72, -1, 3, 18], - "reason": "invalidate paint rectangle" + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [73, 0, 1, 16], + "reason": "caret" } ] }, @@ -62,12 +62,12 @@ ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutTextControl INPUT id='root'", "reason": "subtree" + }, + { + "object": "Caret", + "reason": "caret" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt index deba44d..1b812d7 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
@@ -32,31 +32,12 @@ "object": "LayoutText #text", "rect": [3, 4, 64, 16], "reason": "subtree" - }, - { - "object": "LayoutText #text", - "rect": [64, 4, 3, 16], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [64, 4, 3, 16], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [64, 4, 3, 16], - "reason": "invalidate paint rectangle" } ] } ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutTextControl INPUT id='root'", "reason": "subtree" }, @@ -74,11 +55,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection-after-delete-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection-after-delete-expected.txt index b96665f..4e23b94 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection-after-delete-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection-after-delete-expected.txt
@@ -15,21 +15,6 @@ "object": "LayoutText #text", "rect": [39, 75, 123, 107], "reason": "layoutObject removal" - }, - { - "object": "LayoutBlockFlow DIV id='test'", - "rect": [38, 74, 3, 19], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='test'", - "rect": [38, 74, 3, 19], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutBlockFlow DIV id='test'", - "rect": [38, 74, 3, 19], - "reason": "invalidate paint rectangle" } ] } @@ -40,10 +25,6 @@ "reason": "layoutObject removal" }, { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV id='test'", "reason": "forced by layout" }, @@ -53,11 +34,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutBR BR",
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/tabgroup-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/tabgroup-expected.txt index caba1b3d..4ac861d 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/tabgroup-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/tabgroup-expected.txt
@@ -986,6 +986,42 @@ "reason": "layoutObject removal" }, { + "object": "LayoutSVGPath path", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGPath path id='tabgroupTriangle__0'", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGInlineText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGTSpan tspan", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGInlineText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGTSpan tspan", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGText text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGContainer g id='tabgroupTriangle__0_content'", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGContainer g", + "reason": "layoutObject removal" + }, + { "object": "LayoutSVGContainer g id='tabgroupRect'", "reason": "became visible" },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/textarea-caret-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/textarea-caret-expected.txt index 4956ec6e..2e02823 100644 --- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/textarea-caret-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/textarea-caret-expected.txt
@@ -30,31 +30,12 @@ "object": "LayoutTextControl TEXTAREA id='editor'", "rect": [173, 30, 15, 15], "reason": "scroll" - }, - { - "object": "LayoutText #text", - "rect": [186, 10, 2, 18], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [186, 10, 2, 18], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [186, 10, 2, 18], - "reason": "invalidate paint rectangle" } ] } ], "objectPaintInvalidations": [ { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutTextControl TEXTAREA id='editor'", "reason": "subtree" }, @@ -76,11 +57,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/4776765-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/4776765-expected.txt new file mode 100644 index 0000000..782dcd5 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/4776765-expected.txt
@@ -0,0 +1,54 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV", + "rect": [7, 41, 786, 56], + "reason": "border box change" + }, + { + "object": "LayoutBlockFlow DIV id='div'", + "rect": [8, 78, 784, 18], + "reason": "layoutObject insertion" + }, + { + "object": "LayoutBlockFlow DIV id='div'", + "rect": [8, 60, 1, 17], + "reason": "caret" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutBlockFlow DIV", + "reason": "border box change" + }, + { + "object": "LayoutBlockFlow DIV id='div'", + "reason": "layoutObject insertion" + }, + { + "object": "RootInlineBox", + "reason": "layoutObject insertion" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutBR BR", + "reason": "layoutObject insertion" + }, + { + "object": "InlineTextBox '\n'", + "reason": "layoutObject insertion" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-contenteditable-content-after-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-contenteditable-content-after-expected.txt new file mode 100644 index 0000000..60739a63 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-contenteditable-content-after-expected.txt
@@ -0,0 +1,176 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='editor'", + "rect": [7, 43, 786, 20], + "reason": "style change" + }, + { + "object": "LayoutBlockFlow DIV id='editor'", + "rect": [7, 43, 786, 20], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow DIV id='editor'", + "rect": [7, 43, 786, 20], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow DIV id='editor'", + "rect": [7, 43, 786, 20], + "reason": "forced by layout" + }, + { + "object": "LayoutText #text", + "rect": [8, 44, 23, 17], + "reason": "full" + }, + { + "object": "LayoutText #text", + "rect": [8, 44, 16, 17], + "reason": "full" + }, + { + "object": "LayoutTextFragment (anonymous)", + "rect": [30, 44, 9, 17], + "reason": "forced by layout" + }, + { + "object": "LayoutTextFragment (anonymous)", + "rect": [23, 44, 9, 17], + "reason": "forced by layout" + }, + { + "object": "LayoutTextFragment (anonymous)", + "rect": [23, 44, 9, 17], + "reason": "forced by layout" + }, + { + "object": "LayoutTextFragment (anonymous)", + "rect": [15, 44, 9, 17], + "reason": "forced by layout" + }, + { + "object": "LayoutTextFragment (anonymous)", + "rect": [15, 44, 9, 17], + "reason": "forced by layout" + }, + { + "object": "LayoutText #text", + "rect": [8, 44, 8, 17], + "reason": "layoutObject insertion" + }, + { + "object": "LayoutTextFragment (anonymous)", + "rect": [8, 44, 8, 17], + "reason": "forced by layout" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='editor'", + "reason": "style change" + }, + { + "object": "RootInlineBox", + "reason": "style change" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutBlockFlow DIV id='editor'", + "reason": "forced by layout" + }, + { + "object": "RootInlineBox", + "reason": "forced by layout" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutText #text", + "reason": "layoutObject insertion" + }, + { + "object": "InlineTextBox 'a'", + "reason": "layoutObject insertion" + }, + { + "object": "LayoutTextFragment (anonymous)", + "reason": "forced by layout" + }, + { + "object": "InlineTextBox 'x'", + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow DIV id='editor'", + "reason": "forced by layout" + }, + { + "object": "RootInlineBox", + "reason": "forced by layout" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutText #text", + "reason": "full" + }, + { + "object": "InlineTextBox 'ab'", + "reason": "full" + }, + { + "object": "LayoutTextFragment (anonymous)", + "reason": "forced by layout" + }, + { + "object": "InlineTextBox 'x'", + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow DIV id='editor'", + "reason": "forced by layout" + }, + { + "object": "RootInlineBox", + "reason": "forced by layout" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutText #text", + "reason": "full" + }, + { + "object": "InlineTextBox 'abc'", + "reason": "full" + }, + { + "object": "LayoutTextFragment (anonymous)", + "reason": "forced by layout" + }, + { + "object": "InlineTextBox 'x'", + "reason": "forced by layout" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt new file mode 100644 index 0000000..a86a15a --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt
@@ -0,0 +1,29 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [406, 11, 2, 16], + "reason": "caret" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [403, 11, 2, 16], + "reason": "caret" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-outside-block-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-outside-block-expected.txt new file mode 100644 index 0000000..67cae10c --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-outside-block-expected.txt
@@ -0,0 +1,24 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='target'", + "rect": [791, 8, 1, 17], + "reason": "caret" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll-expected.txt new file mode 100644 index 0000000..1795923f --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-with-composited-scroll-expected.txt
@@ -0,0 +1,70 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true + }, + { + "name": "LayoutBlockFlow DIV id='scroller'", + "position": [8, 44], + "bounds": [100, 100], + "shouldFlattenTransform": false, + "drawsContent": true + }, + { + "name": "Scrolling Layer", + "bounds": [100, 100], + "shouldFlattenTransform": false + }, + { + "name": "Scrolling Contents Layer", + "bounds": [205, 1022], + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='text'", + "rect": [-1, 999, 207, 24], + "reason": "subtree" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [3, 1003, 200, 16], + "reason": "subtree" + } + ] + }, + { + "name": "Overflow Controls Host Layer", + "bounds": [100, 100] + }, + { + "name": "Horizontal Scrollbar Layer", + "position": [0, 100], + "bounds": [100, 0], + "drawsContent": true + }, + { + "name": "Vertical Scrollbar Layer", + "position": [100, 0], + "bounds": [0, 100], + "drawsContent": true + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='text'", + "reason": "subtree" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "reason": "subtree" + }, + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-with-transformation-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-with-transformation-expected.txt new file mode 100644 index 0000000..052f1600 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/caret-with-transformation-expected.txt
@@ -0,0 +1,29 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='div'", + "rect": [347, 211, 10, 17], + "reason": "caret" + }, + { + "object": "LayoutBlockFlow DIV id='div'", + "rect": [43, 36, 10, 16], + "reason": "caret" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/delete-into-nested-block-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/delete-into-nested-block-expected.txt new file mode 100644 index 0000000..5ae8fde --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/delete-into-nested-block-expected.txt
@@ -0,0 +1,115 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='two'", + "rect": [8, 137, 784, 37], + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV", + "rect": [8, 155, 784, 19], + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV", + "rect": [8, 137, 784, 19], + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV id='one'", + "rect": [8, 119, 784, 19], + "reason": "full" + }, + { + "object": "LayoutText #text", + "rect": [8, 155, 32, 18], + "reason": "layoutObject removal" + }, + { + "object": "LayoutText #text", + "rect": [8, 119, 32, 18], + "reason": "layoutObject insertion" + }, + { + "object": "LayoutText #text", + "rect": [8, 137, 28, 18], + "reason": "layoutObject removal" + }, + { + "object": "LayoutText #text", + "rect": [8, 119, 28, 18], + "reason": "layoutObject removal" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV", + "reason": "layoutObject removal" + }, + { + "object": "LayoutText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBR BR", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV id='two'", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBR BR", + "reason": "layoutObject removal" + }, + { + "object": "LayoutText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutInline SPAN", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV id='one'", + "reason": "full" + }, + { + "object": "RootInlineBox", + "reason": "full" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutText #text", + "reason": "layoutObject insertion" + }, + { + "object": "InlineTextBox 'three'", + "reason": "layoutObject insertion" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/inline-outline-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/inline-outline-repaint-expected.txt index c53a139..8debaed 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/inline-outline-repaint-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/inline-outline-repaint-expected.txt
@@ -20,21 +20,6 @@ "object": "LayoutText #text", "rect": [8, 166, 92, 35], "reason": "full" - }, - { - "object": "LayoutText #text", - "rect": [45, 183, 3, 19], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [45, 183, 3, 19], - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutText #text", - "rect": [45, 183, 3, 19], - "reason": "invalidate paint rectangle" } ] } @@ -45,10 +30,6 @@ "reason": "layoutObject removal" }, { - "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutBlockFlow DIV", "reason": "forced by layout" }, @@ -58,11 +39,7 @@ }, { "object": "Caret", - "reason": "invalidate paint rectangle" - }, - { - "object": "Caret", - "reason": "invalidate paint rectangle" + "reason": "caret" }, { "object": "LayoutInline SPAN id='test'",
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt new file mode 100644 index 0000000..233f3e5d --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -0,0 +1,74 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true + }, + { + "name": "LayoutTextControl INPUT id='root'", + "position": [7, 7], + "bounds": [70, 24], + "drawsContent": true, + "backgroundColor": "#FFFFFF", + "paintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='root'", + "rect": [0, 0, 70, 24], + "reason": "subtree" + }, + { + "object": "LayoutTextControl INPUT id='root'", + "rect": [0, 0, 68, 22], + "reason": "full" + } + ] + }, + { + "name": "LayoutBlockFlow DIV id='inner-editor'", + "position": [3, 4], + "bounds": [64, 16], + "shouldFlattenTransform": false, + "drawsContent": true + }, + { + "name": "Scrolling Layer", + "bounds": [64, 16], + "shouldFlattenTransform": false + }, + { + "name": "Scrolling Contents Layer", + "bounds": [75, 16], + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [73, 0, 1, 16], + "reason": "caret" + } + ] + }, + { + "name": "Overflow Controls Host Layer", + "bounds": [64, 16] + }, + { + "name": "Horizontal Scrollbar Layer", + "position": [0, 16], + "bounds": [64, 0], + "drawsContent": true + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='root'", + "reason": "subtree" + }, + { + "object": "Caret", + "reason": "caret" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt new file mode 100644 index 0000000..1b812d7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
@@ -0,0 +1,70 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true + }, + { + "name": "LayoutTextControl INPUT id='root'", + "position": [7, 7], + "bounds": [70, 24], + "drawsContent": true, + "backgroundColor": "#FFFFFF", + "paintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='root'", + "rect": [0, 0, 70, 24], + "reason": "subtree" + }, + { + "object": "LayoutTextControl INPUT id='root'", + "rect": [0, 0, 68, 22], + "reason": "full" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "rect": [3, 4, 64, 16], + "reason": "subtree" + }, + { + "object": "LayoutText #text", + "rect": [3, 4, 64, 16], + "reason": "subtree" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='root'", + "reason": "subtree" + }, + { + "object": "LayoutBlockFlow DIV id='inner-editor'", + "reason": "subtree" + }, + { + "object": "RootInlineBox", + "reason": "subtree" + }, + { + "object": "HorizontalScrollbar", + "reason": "scroll" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutText #text", + "reason": "subtree" + }, + { + "object": "InlineTextBox 'test test test'", + "reason": "subtree" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/selection-after-delete-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/selection-after-delete-expected.txt new file mode 100644 index 0000000..4e23b94 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/selection-after-delete-expected.txt
@@ -0,0 +1,49 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV id='test'", + "rect": [38, 74, 152, 110], + "reason": "forced by layout" + }, + { + "object": "LayoutText #text", + "rect": [39, 75, 123, 107], + "reason": "layoutObject removal" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutBlockFlow DIV id='test'", + "reason": "forced by layout" + }, + { + "object": "RootInlineBox", + "reason": "forced by layout" + }, + { + "object": "Caret", + "reason": "caret" + }, + { + "object": "LayoutBR BR", + "reason": "forced by layout" + }, + { + "object": "InlineTextBox '\n'", + "reason": "forced by layout" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/svg/tabgroup-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/svg/tabgroup-expected.txt index 221f429..db52fc8 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/svg/tabgroup-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/invalidation/svg/tabgroup-expected.txt
@@ -986,6 +986,42 @@ "reason": "layoutObject removal" }, { + "object": "LayoutSVGPath path", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGPath path id='tabgroupTriangle__0'", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGInlineText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGTSpan tspan", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGInlineText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGTSpan tspan", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGText text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGContainer g id='tabgroupTriangle__0_content'", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGContainer g", + "reason": "layoutObject removal" + }, + { "object": "LayoutSVGContainer g id='tabgroupRect'", "reason": "became visible" },
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-compositing-descendant-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-compositing-descendant-expected.png index 4cc4008..e3951651 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-compositing-descendant-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-compositing-descendant-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-ancestor-update-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-ancestor-update-expected.png index 63c36eb..5c9c6699 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-ancestor-update-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-ancestor-update-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt index 567d05ba..c3ceae0 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -3045,6 +3045,7 @@ getter boundingClientRect getter intersectionRatio getter intersectionRect + getter isIntersecting getter rootBounds getter target getter time
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/threaded/compositing/visibility/visibility-simple-video-layer-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/threaded/compositing/visibility/visibility-simple-video-layer-expected.png index 34146f9..5490ee0 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/threaded/compositing/visibility/visibility-simple-video-layer-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/threaded/compositing/visibility/visibility-simple-video-layer-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/media/track/track-cue-rendering-vertical-expected.png b/third_party/WebKit/LayoutTests/platform/win7/media/track/track-cue-rendering-vertical-expected.png index f044bbf..ff1abd0 100644 --- a/third_party/WebKit/LayoutTests/platform/win7/media/track/track-cue-rendering-vertical-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win7/media/track/track-cue-rendering-vertical-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/media/video-layer-crash-expected.png b/third_party/WebKit/LayoutTests/platform/win7/media/video-layer-crash-expected.png index a8422bd..9c6758e9 100644 --- a/third_party/WebKit/LayoutTests/platform/win7/media/video-layer-crash-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win7/media/video-layer-crash-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/media/video-transformed-expected.png b/third_party/WebKit/LayoutTests/platform/win7/media/video-transformed-expected.png index b6e99d4b..05765d9a 100644 --- a/third_party/WebKit/LayoutTests/platform/win7/media/video-transformed-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win7/media/video-transformed-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/plugins/reattach-plugin-during-access.html b/third_party/WebKit/LayoutTests/plugins/reattach-plugin-during-access.html index f7b9775..1e4f213 100644 --- a/third_party/WebKit/LayoutTests/plugins/reattach-plugin-during-access.html +++ b/third_party/WebKit/LayoutTests/plugins/reattach-plugin-during-access.html
@@ -3,11 +3,11 @@ if (window.testRunner) testRunner.dumpAsText(); -function f() { +onload = function() { divElem.appendChild(objElem); objElem[''] = 42; } </script> <div id='divElem'></div> -<object id='objElem' type="text/javascript" onload='f()'></object> +<object id='objElem' type="text/javascript"></object> <p>Test passes if it doesn't crash</p>
diff --git a/third_party/WebKit/LayoutTests/sensor/resources/generic-sensor-tests.js b/third_party/WebKit/LayoutTests/sensor/resources/generic-sensor-tests.js index b0baa2a..8971afa 100644 --- a/third_party/WebKit/LayoutTests/sensor/resources/generic-sensor-tests.js +++ b/third_party/WebKit/LayoutTests/sensor/resources/generic-sensor-tests.js
@@ -17,7 +17,7 @@ return new Promise((resolve, reject) => { let wrapper = new CallbackWrapper(event => { assert_equals(sensorObject.state, 'errored'); - assert_equals(event.error.name, 'NotFoundError'); + assert_equals(event.error.name, 'NotReadableError'); sensorObject.onerror = null; resolve(); }, reject);
diff --git a/third_party/WebKit/LayoutTests/storage/indexeddb/clone-before-keypath-eval.html b/third_party/WebKit/LayoutTests/storage/indexeddb/clone-before-keypath-eval.html deleted file mode 100644 index e7ae292d..0000000 --- a/third_party/WebKit/LayoutTests/storage/indexeddb/clone-before-keypath-eval.html +++ /dev/null
@@ -1,146 +0,0 @@ -<!DOCTYPE html> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> -<script> - -function indexeddb_test(upgrade_func, body_func, description) { - async_test(function(t) { - var dbname = location.pathname + ' - ' + description; - var deleteRequest = indexedDB.deleteDatabase(dbname); - deleteRequest.onsuccess = t.step_func(function() { - var openRequest = indexedDB.open(dbname); - openRequest.onupgradeneeded = t.step_func(function() { - upgrade_func(t, openRequest.result); - }); - openRequest.onsuccess = t.step_func(function() { - body_func(t, openRequest.result); - }); - openRequest.onerror = t.unreached_func('open failed'); - }); - }, description); -} - -function ProbeObject() { - this.id_count = 0; - this.invalid_id_count = 0; - this.prop_count = 0; - Object.defineProperties(this, { - id: { - enumerable: true, - get: function() { - ++this.id_count; - return 1000 + this.id_count; - }}, - invalid_id: { - enumerable: true, - get: function() { - ++this.invalid_id_count; - return {}; - }}, - prop: { - enumerable: true, - get: function() { - ++this.prop_count; - return 2000 + this.prop_count; - }} - }); -} - -indexeddb_test( - function(t, connection) { - connection.createObjectStore( - 'store', {keyPath: 'id', autoIncrement: true}); - }, - function(t, connection) { - var trans = connection.transaction('store', 'readwrite'); - var store = trans.objectStore('store'); - var obj = new ProbeObject(); - store.put(obj); - assert_equals( - obj.id_count, 1, - 'put() operation should access primary key property once'); - assert_equals( - obj.prop_count, 1, - 'put() operation should access other properties once'); - t.done(); - }, 'Key generator and key path validity check operates on a clone'); - -indexeddb_test( - function(t, connection) { - connection.createObjectStore( - 'store', {keyPath: 'invalid_id', autoIncrement: true}); - }, - function(t, connection) { - var trans = connection.transaction('store', 'readwrite'); - var store = trans.objectStore('store'); - var obj = new ProbeObject(); - assert_throws('DataError', function() { store.put(obj); }, - 'put() should throw if primary key cannot be injected'); - assert_equals( - obj.invalid_id_count, 1, - 'put() operation should access primary key property once'); - assert_equals( - obj.prop_count, 1, - 'put() operation should access other properties once'); - t.done(); - }, 'Failing key path validity check operates on a clone'); - -indexeddb_test( - function(t, connection) { - var store = connection.createObjectStore('store'); - store.createIndex('index', 'prop'); - }, - function(t, connection) { - var trans = connection.transaction('store', 'readwrite'); - var store = trans.objectStore('store'); - var obj = new ProbeObject(); - store.put(obj, 'key'); - assert_equals( - obj.prop_count, 1, 'put() should access index key property once'); - assert_equals( - obj.id_count, 1, - 'put() operation should access other properties once'); - t.done(); - }, 'Index key path evaluations operate on a clone'); - -indexeddb_test( - function(t, connection) { - var store = connection.createObjectStore('store', {keyPath: 'id'}); - store.createIndex('index', 'prop'); - }, - function(t, connection) { - var trans = connection.transaction('store', 'readwrite'); - var store = trans.objectStore('store'); - var obj = new ProbeObject(); - store.put(obj); - assert_equals( - obj.id_count, 1, 'put() should access primary key property once'); - assert_equals( - obj.prop_count, 1, 'put() should access index key property once'); - t.done(); - }, 'Store and index key path evaluations operate the same clone'); - -indexeddb_test( - function(t, connection) { - var store = connection.createObjectStore('store', {keyPath: 'id'}); - store.createIndex('index', 'prop'); - }, - function(t, connection) { - var trans = connection.transaction('store', 'readwrite'); - var store = trans.objectStore('store'); - store.put(new ProbeObject()); - - store.openCursor().onsuccess = t.step_func(function(event) { - var cursor = event.target.result; - - var obj = new ProbeObject(); - cursor.update(obj); - assert_equals( - obj.id_count, 1, 'put() should access primary key property once'); - assert_equals( - obj.prop_count, 1, 'put() should access index key property once'); - - t.done(); - }); - }, 'Cursor update checks and keypath evaluations operate on a clone'); -</script>
diff --git a/third_party/WebKit/LayoutTests/storage/indexeddb/deleteDatabase-event.html b/third_party/WebKit/LayoutTests/storage/indexeddb/deleteDatabase-event.html deleted file mode 100644 index 0cf1659..0000000 --- a/third_party/WebKit/LayoutTests/storage/indexeddb/deleteDatabase-event.html +++ /dev/null
@@ -1,50 +0,0 @@ -<!DOCTYPE html> -<title>IndexedDB: Verify deleteDatabase success event</title> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> -<script> -(function() { - var t = async_test('deleteDatabase success event type, existing DB'); - t.step(function() { - var dbName = 'db' + location.pathname; - var openRequest = indexedDB.open(dbName, 9); - openRequest.onsuccess = t.step_func(function(e) { - var db = openRequest.result; - db.close(); - - var deleteRequest = indexedDB.deleteDatabase(dbName); - deleteRequest.onsuccess = t.step_func(function(e) { - assert_equals(deleteRequest.result, undefined, - '...the implementation must set the result of the request to undefined...'); - assert_true(e instanceof IDBVersionChangeEvent, - 'The event must implement the IDBVersionChangeEvent interface ...'); - assert_equals(e.oldVersion, 9, - 'and have oldVersion set to database version...'); - assert_equals(e.newVersion, null, - 'and have the newVersion property set to null.'); - t.done(); - }); - }); - }); -}()); - -(function() { - var t = async_test('deleteDatabase success event, non-existent DB'); - t.step(function() { - - var dbName = 'db' + location.pathname + '-does-not-exist'; - var deleteRequest = indexedDB.deleteDatabase(dbName); - deleteRequest.onsuccess = t.step_func(function(e) { - assert_equals(deleteRequest.result, undefined, - '...the implementation must set the result of the request to undefined...'); - assert_true(e instanceof IDBVersionChangeEvent, - 'The event must implement the IDBVersionChangeEvent interface ...'); - assert_equals(e.oldVersion, 0, - 'and have oldVersion set to database version...'); - assert_equals(e.newVersion, null, - 'and have the newVersion property set to null.'); - t.done(); - }); - }); -}()); -</script>
diff --git a/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt b/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt index bdf60ad..8366e38 100644 --- a/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt
@@ -236,7 +236,7 @@ r: 0px resize: none right: auto -rotate: 0deg +rotate: none rx: auto ry: auto scale: none
diff --git a/third_party/WebKit/LayoutTests/svg/masking/mask-valid-reference-wrong-element-type-crash-expected.txt b/third_party/WebKit/LayoutTests/svg/masking/mask-valid-reference-wrong-element-type-crash-expected.txt new file mode 100644 index 0000000..2f76b672 --- /dev/null +++ b/third_party/WebKit/LayoutTests/svg/masking/mask-valid-reference-wrong-element-type-crash-expected.txt
@@ -0,0 +1 @@ +PASS if no crash in debug
diff --git a/third_party/WebKit/LayoutTests/svg/masking/mask-valid-reference-wrong-element-type-crash.html b/third_party/WebKit/LayoutTests/svg/masking/mask-valid-reference-wrong-element-type-crash.html new file mode 100644 index 0000000..8c93c24 --- /dev/null +++ b/third_party/WebKit/LayoutTests/svg/masking/mask-valid-reference-wrong-element-type-crash.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<svg mask="url(#f)"> + <filter id="f"/> +</svg> +<p>PASS if no crash in debug</p> +<script> +if (window.testRunner) + testRunner.dumpAsText(); +</script>
diff --git a/third_party/WebKit/LayoutTests/transforms/rotate-parsing.html b/third_party/WebKit/LayoutTests/transforms/rotate-parsing.html index eb8a7d8..ecda541 100644 --- a/third_party/WebKit/LayoutTests/transforms/rotate-parsing.html +++ b/third_party/WebKit/LayoutTests/transforms/rotate-parsing.html
@@ -6,9 +6,10 @@ <script> expect = expect.bind(this, 'rotate', 'rotate'); -expect('initial').parsesAs('initial').isComputedTo('0deg'); +expect('initial').parsesAs('initial').isComputedTo('none'); expect('inherit').parsesAs('inherit'); +expect('none').parsesAs('none').isComputedTo('none'); expect('10deg').parsesAs('10deg').isComputedTo('10deg'); expect('0 0 1 10deg').parsesAs('0 0 1 10deg').isComputedTo('10deg'); expect('-1.5 2 3 10deg').parsesAs('-1.5 2 3 10deg').isComputedTo('-1.5 2 3 10deg'); @@ -21,7 +22,6 @@ expect('0 calc(0.5 + 0.5) 1 calc(1turn - 270deg + 400grad)').parsesAs('0 1 1 calc(450deg)').isComputedTo('0 1 1 450deg'); expect('2').isInvalid(); -expect('none').isInvalid(); expect('1 2deg').isInvalid(); expect('1 2 45deg').isInvalid(); expect('1 2 3 4 45deg').isInvalid();
diff --git a/third_party/WebKit/LayoutTests/transforms/scale-parsing.html b/third_party/WebKit/LayoutTests/transforms/scale-parsing.html index 4e4bdeb..70761c3 100644 --- a/third_party/WebKit/LayoutTests/transforms/scale-parsing.html +++ b/third_party/WebKit/LayoutTests/transforms/scale-parsing.html
@@ -9,6 +9,7 @@ expect('initial').parsesAs('initial').isComputedTo('none'); expect('inherit').parsesAs('inherit'); +expect('none').parsesAs('none').isComputedTo('none'); expect('1').parsesAs('1').isComputedTo('1'); expect('1 -2.3').parsesAs('1 -2.3').isComputedTo('1 -2.3'); expect('1 -2.3 4').parsesAs('1 -2.3 4').isComputedTo('1 -2.3 4');
diff --git a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/alpha-expected.txt b/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/alpha-expected.txt deleted file mode 100644 index 6ef91db..0000000 --- a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/alpha-expected.txt +++ /dev/null
@@ -1,31 +0,0 @@ -Series of tests for canvas alpha - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS ctx1.getContextAttributes().alpha is true -PASS imgData1.data[0] is 0 -PASS imgData1.data[1] is 0 -PASS imgData1.data[2] is 0 -PASS imgData1.data[3] is 0 -PASS ctx2.getContextAttributes().alpha is true -PASS imgData2.data[0] is 0 -PASS imgData2.data[1] is 0 -PASS imgData2.data[2] is 0 -PASS imgData2.data[3] is 0 -PASS ctx3.getContextAttributes().alpha is false -PASS ctx4.getContextAttributes().alpha is true -PASS imgData4.data[0] is 0 -PASS imgData4.data[1] is 0 -PASS imgData4.data[2] is 0 -PASS imgData4.data[3] is 0 -PASS attrs.alpha is true -PASS ctx4.getContextAttributes().alpha is true -PASS imgData4.data[0] is 0 -PASS imgData4.data[1] is 0 -PASS imgData4.data[2] is 0 -PASS imgData4.data[3] is 0 -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-tail.html b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-tail.html index e875390..0b942a11 100644 --- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-tail.html +++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquad-tail.html
@@ -4,7 +4,6 @@ <title>Test Biquad Tail Output</title> <script src="../../resources/testharness.js"></script> <script src="../../resources/testharnessreport.js"></script> - <script src="../../resources/js-test.js"></script> <script src="../resources/audit-util.js"></script> <script src="../resources/audit.js"></script> </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-expected.txt deleted file mode 100644 index f494492..0000000 --- a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-expected.txt +++ /dev/null
@@ -1,14 +0,0 @@ -Tests attribute and basic functionality of Delay. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - -PASS delay.numberOfInputs === 1 is true -PASS delay.numberOfOutputs === 1 is true -PASS delay.delayTime.defaultValue === 0.0 is true -PASS delay.delayTime.value === 0.0 is true -PASS delay.delayTime.value === 0.5 is true -PASS Test signal was correctly delayed by 0.5 sec. -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-default-delay-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-default-delay-expected.txt deleted file mode 100644 index f022b90..0000000 --- a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-default-delay-expected.txt +++ /dev/null
@@ -1,9 +0,0 @@ -Tests DelayNode with delay set to default maximum delay. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - -PASS Test signal was correctly delayed by 1 sec. -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-default-delay.html b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-default-delay.html index c0589ee..a9ad29f5 100644 --- a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-default-delay.html +++ b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-default-delay.html
@@ -2,28 +2,20 @@ <html> <head> -<script src="../../resources/js-test.js"></script> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <script src="../resources/audit-util.js"></script> -<script src="../resources/audio-testing.js"></script> +<script src="../resources/audit.js"></script> <script src="../resources/delay-testing.js"></script> </head> <body> - -<div id="description"></div> -<div id="console"></div> - <script> -description("Tests DelayNode with delay set to default maximum delay."); +let audit = Audit.createTaskRunner(); -function runTest() { - if (window.testRunner) { - testRunner.dumpAsText(); - testRunner.waitUntilDone(); - } - - window.jsTestIsAsync = true; - +audit.define("test", function (task, should) { + task.describe("DelayNode with delay set to default maximum delay"); + // Create offline audio context. var context = new OfflineAudioContext(1, sampleRate * renderLengthSeconds, sampleRate); var toneBuffer = createToneBuffer(context, 20, 20 * toneLengthSeconds, sampleRate); // 20Hz tone @@ -39,11 +31,12 @@ delay.connect(context.destination); bufferSource.start(0); - context.oncomplete = checkDelayedResult(toneBuffer); - context.startRendering(); -} + context.startRendering() + .then(buffer => checkDelayedResult(buffer, toneBuffer, should)) + .then(() => task.done()); +}); -runTest(); +audit.run(); </script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-nondefault-delay-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-nondefault-delay-expected.txt deleted file mode 100644 index 13e30f2..0000000 --- a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-nondefault-delay-expected.txt +++ /dev/null
@@ -1,9 +0,0 @@ -Tests DelayNode with delay set to non-default maximum delay. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - -PASS Test signal was correctly delayed by 1.5 sec. -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-nondefault-delay.html b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-nondefault-delay.html index 13f9b97..5a86b82 100644 --- a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-nondefault-delay.html +++ b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-max-nondefault-delay.html
@@ -2,28 +2,20 @@ <html> <head> -<script src="../../resources/js-test.js"></script> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <script src="../resources/audit-util.js"></script> -<script src="../resources/audio-testing.js"></script> +<script src="../resources/audit.js"></script> <script src="../resources/delay-testing.js"></script> </head> <body> - -<div id="description"></div> -<div id="console"></div> - <script> -description("Tests DelayNode with delay set to non-default maximum delay."); +let audit = Audit.createTaskRunner(); -function runTest() { - if (window.testRunner) { - testRunner.dumpAsText(); - testRunner.waitUntilDone(); - } - - window.jsTestIsAsync = true; - +audit.define("test", function (task, should) { + task.describe("DelayNode with delay set to non-default maximum delay"); + // Create offline audio context. var context = new OfflineAudioContext(1, sampleRate * renderLengthSeconds, sampleRate); var toneBuffer = createToneBuffer(context, 20, 20 * toneLengthSeconds, sampleRate); // 20Hz tone @@ -40,12 +32,12 @@ delay.connect(context.destination); bufferSource.start(0); - context.oncomplete = checkDelayedResult(toneBuffer); - context.startRendering(); -} + context.startRendering() + .then(buffer => checkDelayedResult(buffer, toneBuffer, should)) + .then(() => task.done());; +}); -runTest(); - +audit.run(); </script> </body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelay-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelay-expected.txt deleted file mode 100644 index c7b17098..0000000 --- a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelay-expected.txt +++ /dev/null
@@ -1,9 +0,0 @@ -Tests basic functionality of DelayNode with a non-default max delay time. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - -PASS Test signal was correctly delayed by 1.5 sec. -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelay.html b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelay.html index f9c17fb5..cafb81d 100644 --- a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelay.html +++ b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelay.html
@@ -2,27 +2,20 @@ <html> <head> -<script src="../../resources/js-test.js"></script> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <script src="../resources/audit-util.js"></script> -<script src="../resources/audio-testing.js"></script> +<script src="../resources/audit.js"></script> <script src="../resources/delay-testing.js"></script> </head> <body> - -<div id="description"></div> -<div id="console"></div> - <script> -description("Tests basic functionality of DelayNode with a non-default max delay time."); +let audit = Audit.createTaskRunner(); -function runTest() { - if (window.testRunner) { - testRunner.dumpAsText(); - testRunner.waitUntilDone(); - } - - window.jsTestIsAsync = true; +audit.define("test", function (task, should) { + task.describe( + "Basic functionality of DelayNode with a non-default max delay time") // Create offline audio context. var context = new OfflineAudioContext(1, sampleRate * renderLengthSeconds, sampleRate); @@ -42,12 +35,12 @@ delay.connect(context.destination); bufferSource.start(0); - context.oncomplete = checkDelayedResult(toneBuffer); - context.startRendering(); -} + context.startRendering() + .then(buffer => checkDelayedResult(buffer, toneBuffer, should)) + .then(() => task.done()); +}); -runTest(); - +audit.run(); </script> </body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelaylimit-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelaylimit-expected.txt deleted file mode 100644 index bda14d0..0000000 --- a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelaylimit-expected.txt +++ /dev/null
@@ -1,14 +0,0 @@ -Tests attribute and maximum allowed delay of DelayNode. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - -PASS context.createDelay(180) threw exception NotSupportedError: Failed to execute 'createDelay' on 'BaseAudioContext': The max delay time provided (180) is outside the range (0, 180).. -PASS context.createDelay(0) threw exception NotSupportedError: Failed to execute 'createDelay' on 'BaseAudioContext': The max delay time provided (0) is outside the range (0, 180).. -PASS context.createDelay(-1) threw exception NotSupportedError: Failed to execute 'createDelay' on 'BaseAudioContext': The max delay time provided (-1) is outside the range (0, 180).. -PASS context.createDelay(NaN) threw exception TypeError: Failed to execute 'createDelay' on 'BaseAudioContext': The provided double value is non-finite.. -PASS delay.delayTime.value === 0.5 is true -PASS Test signal was correctly delayed by 0.5 sec. -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelaylimit.html b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelaylimit.html index 278bd43..fe477bc 100644 --- a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelaylimit.html +++ b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-maxdelaylimit.html
@@ -2,27 +2,19 @@ <html> <head> -<script src="../../resources/js-test.js"></script> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <script src="../resources/audit-util.js"></script> -<script src="../resources/audio-testing.js"></script> +<script src="../resources/audit.js"></script> <script src="../resources/delay-testing.js"></script> </head> <body> - -<div id="description"></div> -<div id="console"></div> - <script> -description("Tests attribute and maximum allowed delay of DelayNode."); +let audit = Audit.createTaskRunner(); -function runTest() { - if (window.testRunner) { - testRunner.dumpAsText(); - testRunner.waitUntilDone(); - } - - window.jsTestIsAsync = true; +audit.define("test", function (task, should) { + task.describe("Tests attribute and maximum allowed delay of DelayNode"); // Create offline audio context. var context = new OfflineAudioContext(1, sampleRate * renderLengthSeconds, sampleRate); @@ -32,25 +24,32 @@ bufferSource.buffer = toneBuffer; window.context = context; - shouldThrow("context.createDelay(180)"); - shouldThrow("context.createDelay(0)"); - shouldThrow("context.createDelay(-1)"); - shouldThrow("context.createDelay(NaN)"); - + should(() => context.createDelay(180)) + .throw(); + should(() => context.createDelay(0)) + .throw(); + should(() => context.createDelay(-1)) + .throw(); + should(() => context.createDelay(NaN)) + .throw(); +; var delay = context.createDelay(179); delay.delayTime.value = delayTimeSeconds; window.delay = delay; - shouldBeTrue("delay.delayTime.value === 0.5"); + should(delay.delayTime.value, + "delay.delayTime.value = " + delayTimeSeconds) + .beEqualTo(delayTimeSeconds); bufferSource.connect(delay); delay.connect(context.destination); bufferSource.start(0); - context.oncomplete = checkDelayedResult(toneBuffer); - context.startRendering(); -} + context.startRendering() + .then(buffer => checkDelayedResult(buffer, toneBuffer, should)) + .then(() => task.done()); +}); -runTest(); +audit.run(); </script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-scheduling-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-scheduling-expected.txt deleted file mode 100644 index 791ea43..0000000 --- a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-scheduling-expected.txt +++ /dev/null
@@ -1,9 +0,0 @@ -Tests that DelayNode delayTime parameter can be scheduled at a given time. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - -PASS Test signal was correctly delayed by 0.5 sec. -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-scheduling.html b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-scheduling.html index 255d329a..d8f3cd5 100644 --- a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-scheduling.html +++ b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode-scheduling.html
@@ -2,28 +2,20 @@ <html> <head> -<script src="../../resources/js-test.js"></script> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <script src="../resources/audit-util.js"></script> -<script src="../resources/audio-testing.js"></script> +<script src="../resources/audit.js"></script> <script src="../resources/delay-testing.js"></script> </head> <body> - -<div id="description"></div> -<div id="console"></div> - <script> -description("Tests that DelayNode delayTime parameter can be scheduled at a given time."); +let audit = Audit.createTaskRunner(); -function runTest() { - if (window.testRunner) { - testRunner.dumpAsText(); - testRunner.waitUntilDone(); - } - - window.jsTestIsAsync = true; - +audit.define("test", function (task, should) { + task.describe("DelayNode delayTime parameter can be scheduled at a given time"); + // Create offline audio context. var context = new OfflineAudioContext(1, sampleRate * renderLengthSeconds, sampleRate); var toneBuffer = createToneBuffer(context, 20, 20 * toneLengthSeconds, sampleRate); // 20Hz tone @@ -40,11 +32,12 @@ delay.connect(context.destination); bufferSource.start(0); - context.oncomplete = checkDelayedResult(toneBuffer); - context.startRendering(); -} + context.startRendering() + .then(buffer => checkDelayedResult(buffer, toneBuffer, should)) + .then(() => task.done()); +}); -runTest(); +audit.run(); </script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode.html b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode.html index df29c186..501157d 100644 --- a/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode.html +++ b/third_party/WebKit/LayoutTests/webaudio/Delay/delaynode.html
@@ -2,55 +2,53 @@ <html> <head> -<script src="../../resources/js-test.js"></script> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <script src="../resources/audit-util.js"></script> -<script src="../resources/audio-testing.js"></script> +<script src="../resources/audit.js"></script> <script src="../resources/delay-testing.js"></script> </head> <body> - -<div id="description"></div> -<div id="console"></div> - <script> -description("Tests attribute and basic functionality of Delay."); +let audit = Audit.createTaskRunner(); -function runTest() { - if (window.testRunner) { - testRunner.dumpAsText(); - testRunner.waitUntilDone(); - } - - window.jsTestIsAsync = true; - +audit.define("test", function (task, should) { + task.describe("Tests attribute and basic functionality of DelayNode"); + // Create offline audio context. - var context = new OfflineAudioContext(1, sampleRate * renderLengthSeconds, sampleRate); - var toneBuffer = createToneBuffer(context, 20, 20 * toneLengthSeconds, sampleRate); // 20Hz tone + let context = new OfflineAudioContext(1, sampleRate * renderLengthSeconds, sampleRate); + let toneBuffer = createToneBuffer(context, 20, 20 * toneLengthSeconds, sampleRate); // 20Hz tone - var bufferSource = context.createBufferSource(); + let bufferSource = context.createBufferSource(); bufferSource.buffer = toneBuffer; - var delay = context.createDelay(); + let delay = context.createDelay(); window.delay = delay; - shouldBeTrue("delay.numberOfInputs === 1"); - shouldBeTrue("delay.numberOfOutputs === 1"); - shouldBeTrue("delay.delayTime.defaultValue === 0.0"); - shouldBeTrue("delay.delayTime.value === 0.0"); + should(delay.numberOfInputs, "delay.numberOfInputs") + .beEqualTo(1); + should(delay.numberOfOutputs, "delay.numberOfOutputs") + .beEqualTo(1); + should(delay.delayTime.defaultValue, "delay.delayTime.defaultValue") + .beEqualTo(0.0); + should(delay.delayTime.value, "delay.delayTime.value") + .beEqualTo(0.0); delay.delayTime.value = delayTimeSeconds; - shouldBeTrue("delay.delayTime.value === 0.5"); + should(delay.delayTime.value, "delay.delayTime.value = " + delayTimeSeconds) + .beEqualTo(delayTimeSeconds); bufferSource.connect(delay); delay.connect(context.destination); bufferSource.start(0); - context.oncomplete = checkDelayedResult(toneBuffer); - context.startRendering(); -} + context.startRendering() + .then(buffer => checkDelayedResult(buffer, toneBuffer, should)) + .then(task.done.bind(task)); +}); -runTest(); +audit.run(); </script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-custom-sweep-snr-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-custom-sweep-snr-expected.txt deleted file mode 100644 index aee25e32..0000000 --- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-custom-sweep-snr-expected.txt +++ /dev/null
@@ -1,13 +0,0 @@ -CONSOLE WARNING: line 101: Oscillator.frequency.exponentialRampToValue value 24050 outside nominal range [-22050, 22050]; value will be clamped. -Test Custom Oscillator with Exponential Sweep - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS Exceeded SNR threshold of 80.21 dB -PASS Maximum difference below threshold of 4.88 ulp (16-bits) -PASS Number of differences between actual and expected result is less than 15016 out of 176400 -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-custom-sweep-snr.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-custom-sweep-snr.html index 076beee..ca8bda5 100644 --- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-custom-sweep-snr.html +++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-custom-sweep-snr.html
@@ -2,21 +2,34 @@ <html> <head> <title>Test Oscillator Node: custom</title> + <script src="../../resources/testharness.js"></script> + <script src="../../resources/testharnessreport.js"></script> + <script src="../resources/audit-util.js"></script> + <script src="../resources/audit.js"></script> <script src="../resources/buffer-loader.js"></script> - <script src="../../resources/js-test.js"></script> <script src="../resources/oscillator-testing.js"></script> </head> <body> <script> - description("Test Custom Oscillator with Exponential Sweep"); - + let audit = Audit.createTaskRunner(); var tester = OscillatorTestingUtils; - // The thresholds are experimentally determined. - tester.setThresholds({snr: 80.21, maxDiff: 4.88, diffCount: 15016}); - tester.runTest("custom"); - successfullyParsed = true; + audit.define("test", (task, should) => { + let context = new OfflineAudioContext(1, tester.sampleRate * + tester.lengthInSeconds, tester.sampleRate); + + // The thresholds are experimentally determined. + tester.setThresholds({ + snr: 80.21, + maxDiff: 4.88, + diffCount: 15016 + }); + tester.runTest(context, "custom", + "Custom Oscillator with Exponential Sweep", task, should); + }); + + audit.run(); </script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sawtooth-sweep-snr-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sawtooth-sweep-snr-expected.txt deleted file mode 100644 index cada2f39..0000000 --- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sawtooth-sweep-snr-expected.txt +++ /dev/null
@@ -1,13 +0,0 @@ -CONSOLE WARNING: line 101: Oscillator.frequency.exponentialRampToValue value 24050 outside nominal range [-22050, 22050]; value will be clamped. -Test Sawtooth Oscillator with Exponential Sweep - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS Exceeded SNR threshold of 80 dB -PASS Maximum difference below threshold of 4.06 ulp (16-bits) -PASS Number of differences between actual and expected result is less than 15827 out of 176400 -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sawtooth-sweep-snr.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sawtooth-sweep-snr.html index 5015fd7..a38d206 100644 --- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sawtooth-sweep-snr.html +++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sawtooth-sweep-snr.html
@@ -2,21 +2,35 @@ <html> <head> <title>Test Oscillator Node: sawtooth</title> + <script src="../../resources/testharness.js"></script> + <script src="../../resources/testharnessreport.js"></script> + <script src="../resources/audit-util.js"></script> + <script src="../resources/audit.js"></script> <script src="../resources/buffer-loader.js"></script> - <script src="../../resources/js-test.js"></script> <script src="../resources/oscillator-testing.js"></script> </head> <body> <script> - description("Test Sawtooth Oscillator with Exponential Sweep"); + let audit = Audit.createTaskRunner(); + let tester = OscillatorTestingUtils; - var tester = OscillatorTestingUtils; + audit.define("test", (task, should) => { + let context = new OfflineAudioContext(1, tester.sampleRate * + tester.lengthInSeconds, tester.sampleRate); - // The thresholds are experimentally determined. - tester.setThresholds({snr: 80.00, maxDiff: 4.06, diffCount: 15827}); - tester.runTest("sawtooth"); - successfullyParsed = true; + // The thresholds are experimentally determined. + tester.setThresholds({ + snr: 80.00, + maxDiff: 4.06, + diffCount: 15827 + }); + tester.runTest(context, "sawtooth", + "Sawtooth Oscillator with Exponential Sweep", + task, should); + }); + + audit.run(); </script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sine-sweep-snr-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sine-sweep-snr-expected.txt deleted file mode 100644 index b13dea8..0000000 --- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sine-sweep-snr-expected.txt +++ /dev/null
@@ -1,13 +0,0 @@ -CONSOLE WARNING: line 101: Oscillator.frequency.exponentialRampToValue value 24050 outside nominal range [-22050, 22050]; value will be clamped. -Test Sine Oscillator with Exponential Sweep - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS Exceeded SNR threshold of 81.05 dB -PASS Maximum difference below threshold of 6.78 ulp (16-bits) -PASS Number of differences between actual and expected result is less than 17608 out of 176400 -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sine-sweep-snr.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sine-sweep-snr.html index 26bda2a..c3a864da 100644 --- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sine-sweep-snr.html +++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sine-sweep-snr.html
@@ -2,21 +2,35 @@ <html> <head> <title>Test Oscillator Node: sine</title> + <script src="../../resources/testharness.js"></script> + <script src="../../resources/testharnessreport.js"></script> + <script src="../resources/audit-util.js"></script> + <script src="../resources/audit.js"></script> <script src="../resources/buffer-loader.js"></script> - <script src="../../resources/js-test.js"></script> <script src="../resources/oscillator-testing.js"></script> </head> <body> <script> - description("Test Sine Oscillator with Exponential Sweep"); - - var tester = OscillatorTestingUtils; + let audit = Audit.createTaskRunner(); + let tester = OscillatorTestingUtils; - // The thresholds are experimentally determined. - tester.setThresholds({snr: 81.05, maxDiff: 6.78, diffCount: 17608}); - tester.runTest("sine"); - successfullyParsed = true; + audit.define("test", (task, should) => { + let context = new OfflineAudioContext(1, tester.sampleRate * + tester.lengthInSeconds, tester.sampleRate); + + // The thresholds are experimentally determined. + tester.setThresholds({ + snr: 81.05, + maxDiff: 6.78, + diffCount: 17608 + }); + tester.runTest(context, "sine", + "Sine Oscillator with Exponential Sweep", + task, should); + }); + + audit.run(); </script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-square-sweep-snr-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-square-sweep-snr-expected.txt deleted file mode 100644 index 4d99208..0000000 --- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-square-sweep-snr-expected.txt +++ /dev/null
@@ -1,13 +0,0 @@ -CONSOLE WARNING: line 101: Oscillator.frequency.exponentialRampToValue value 24050 outside nominal range [-22050, 22050]; value will be clamped. -Test Square Oscillator with Exponential Sweep - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS Exceeded SNR threshold of 81.57 dB -PASS Maximum difference below threshold of 7.26 ulp (16-bits) -PASS Number of differences between actual and expected result is less than 18260 out of 176400 -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-square-sweep-snr.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-square-sweep-snr.html index baa4eca..ec4383b 100644 --- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-square-sweep-snr.html +++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-square-sweep-snr.html
@@ -2,22 +2,34 @@ <html> <head> <title>Test Oscillator Node: square</title> + <script src="../../resources/testharness.js"></script> + <script src="../../resources/testharnessreport.js"></script> + <script src="../resources/audit-util.js"></script> + <script src="../resources/audit.js"></script> <script src="../resources/buffer-loader.js"></script> - <script src="../../resources/js-test.js"></script> <script src="../resources/oscillator-testing.js"></script> </head> <body> <script> - description("Test Square Oscillator with Exponential Sweep"); + let audit = Audit.createTaskRunner(); + let tester = OscillatorTestingUtils; - // Thresholds for verifying the test passes. The thresholds are experimentally determined. + audit.define("test", (task, should) => { + let context = new OfflineAudioContext(1, tester.sampleRate * + tester.lengthInSeconds, tester.sampleRate); - var tester = OscillatorTestingUtils; - // The thresholds are experimentally determined. - tester.setThresholds({snr: 81.57, maxDiff: 7.26, diffCount: 18260}); - tester.runTest("square"); - successfullyParsed = true; + // The thresholds are experimentally determined. + tester.setThresholds({ + snr: 81.57, + maxDiff: 7.26, + diffCount: 18260 + }); + tester.runTest(context, "square", + "Square Oscillator with Exponential Sweep", task, should); + }); + + audit.run(); </script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-triangle-sweep-snr-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-triangle-sweep-snr-expected.txt deleted file mode 100644 index 3435336..0000000 --- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-triangle-sweep-snr-expected.txt +++ /dev/null
@@ -1,13 +0,0 @@ -CONSOLE WARNING: line 101: Oscillator.frequency.exponentialRampToValue value 24050 outside nominal range [-22050, 22050]; value will be clamped. -Test Triangle Oscillator with Exponential Sweep - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS Exceeded SNR threshold of 80.5 dB -PASS Maximum difference below threshold of 5.71 ulp (16-bits) -PASS Number of differences between actual and expected result is less than 16982 out of 176400 -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-triangle-sweep-snr.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-triangle-sweep-snr.html index 544e859..f32e3ca 100644 --- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-triangle-sweep-snr.html +++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-triangle-sweep-snr.html
@@ -2,21 +2,35 @@ <html> <head> <title>Test Oscillator Node: triangle</title> + <script src="../../resources/testharness.js"></script> + <script src="../../resources/testharnessreport.js"></script> + <script src="../resources/audit-util.js"></script> + <script src="../resources/audit.js"></script> <script src="../resources/buffer-loader.js"></script> - <script src="../../resources/js-test.js"></script> <script src="../resources/oscillator-testing.js"></script> </head> <body> <script> - description("Test Triangle Oscillator with Exponential Sweep"); + let audit = Audit.createTaskRunner(); + let tester = OscillatorTestingUtils; - // Thresholds for verifying the test passes. The thresholds are experimentally determined. - - var tester = OscillatorTestingUtils; - tester.setThresholds({snr: 80.50, maxDiff: 5.71, diffCount: 16982}); - tester.runTest("triangle"); - successfullyParsed = true; + audit.define("test", (task, should) => { + let context = new OfflineAudioContext(1, tester.sampleRate * + tester.lengthInSeconds, tester.sampleRate); + + // Thresholds for verifying the test passes. The thresholds are + // experimentally determined. + tester.setThresholds({ + snr: 80.50, + maxDiff: 5.71, + diffCount: 16982 + }); + tester.runTest(context, "triangle", + "Triangle Oscillator with Exponential Sweep ", task, should); + }); + + audit.run(); </script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-basic-expected.txt deleted file mode 100644 index 5cda5b9..0000000 --- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-basic-expected.txt +++ /dev/null
@@ -1,18 +0,0 @@ -CONSOLE WARNING: line 64: The provided value '0' is not a valid enum value of type OscillatorType. -Basic test of setting Oscillator node types. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - -PASS osc.type = 'sine' is equal to "sine". -PASS osc.type = 'square' is equal to "square". -PASS osc.type = 'sawtooth' is equal to "sawtooth". -PASS osc.type = 'triangle' is equal to "triangle". -PASS osc.type = 'custom' threw InvalidStateError: Failed to set the 'type' property on 'OscillatorNode': 'type' cannot be set directly to 'custom'. Use setPeriodicWave() to create a custom Oscillator type.. -PASS osc.setPeriodicWave(wave) did not throw an exception. -PASS osc.type is equal to "custom". -PASS osc.type = 0 is not equal to 0. -PASS osc.type is equal to "custom". -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-basic.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-basic.html index c98186e..852d9987d 100644 --- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-basic.html +++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-basic.html
@@ -5,18 +5,14 @@ --> <html> <head> -<script src="../../resources/js-test.js"></script> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <script src="../resources/audit-util.js"></script> <script src="../resources/audio-testing.js"></script> </head> <body> -<div id="description"></div> -<div id="console"></div> - <script> -description("Basic test of setting Oscillator node types."); - var sampleRate = 44100; var renderLengthSeconds = 0.25; @@ -24,13 +20,6 @@ function runTest() { - if (window.testRunner) { - testRunner.dumpAsText(); - testRunner.waitUntilDone(); - } - - window.jsTestIsAsync = true; - // Create offline audio context. var context = new OfflineAudioContext(2, sampleRate * renderLengthSeconds, sampleRate); var osc = context.createOscillator(); @@ -64,13 +53,9 @@ osc.type = 0; Should("osc.type = 0", osc.type).notBeEqualTo(0); Should("osc.type", osc.type).beEqualTo(oldType); - - finishJSTest(); } runTest(); -successfullyParsed = true; - </script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-ended-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-ended-expected.txt deleted file mode 100644 index fd84d92..0000000 --- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-ended-expected.txt +++ /dev/null
@@ -1,9 +0,0 @@ -Tests that OscillatorNode calls its onended EventListener. -PASS successfullyParsed is true - -TEST COMPLETE -PASS osc.onended called. -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-ended.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-ended.html index ba51ccb..72ab789d 100644 --- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-ended.html +++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-ended.html
@@ -1,19 +1,19 @@ <!DOCTYPE html> <head> - <script src="../../resources/js-test.js"></script> + <script src="../../resources/testharness.js"></script> + <script src="../../resources/testharnessreport.js"></script> <script src="../resources/audit-util.js"></script> - <script src="../resources/audio-testing.js"></script> + <script src="../resources/audit.js"></script> <script src="../resources/audiobuffersource-testing.js"></script> +</head> +<body> <script> + var audit = Audit.createTaskRunner(); + var context; var source; - function runTest() - { - if (window.testRunner) { - testRunner.dumpAsText(); - testRunner.waitUntilDone(); - } + audit.define("test", function (task, should) { var sampleRate = 44100.0; var lengthInSeconds = 0.1; @@ -23,19 +23,15 @@ osc.connect(context.destination); osc.onended = function() { - testPassed("osc.onended called."); - finishJSTest(); - if (window.testRunner) - testRunner.notifyDone(); - + should(true, "osc.onended was called") + .beTrue(); + task.done(); } osc.start(0); osc.stop(0.1); context.startRendering(); - } + }); + + audit.run(); </script> -</head> -<body onload="runTest()"> - <div>Tests that OscillatorNode calls its onended EventListener.</div> - <div id="console"></div> </body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-contexts-expected.txt b/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-contexts-expected.txt deleted file mode 100644 index cdea5022..0000000 --- a/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-contexts-expected.txt +++ /dev/null
@@ -1,13 +0,0 @@ -CONSOLE WARNING: line 101: Oscillator.frequency.exponentialRampToValue value 24050 outside nominal range [-22050, 22050]; value will be clamped. -Test Builtin Oscillator PeriodicWave Tables - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS Exceeded SNR threshold of 80 dB -PASS Maximum difference below threshold of 4.06 ulp (16-bits) -PASS Number of differences between actual and expected result is less than 15827 out of 176400 -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-contexts.html b/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-contexts.html index 5ae37760..9e16ba8e 100644 --- a/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-contexts.html +++ b/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-contexts.html
@@ -2,32 +2,45 @@ <html> <head> <title>Test Oscillator Node: sawtooth</title> - <script src="../../resources/js-test.js"></script> + <script src="../../resources/testharness.js"></script> + <script src="../../resources/testharnessreport.js"></script> + <script src="../resources/audit-util.js"></script> + <script src="../resources/audit.js"></script> <script src="../resources/buffer-loader.js"></script> <script src="../resources/oscillator-testing.js"></script> </head> <body> <script> - description("Test Builtin Oscillator PeriodicWave Tables"); + let audit = Audit.createTaskRunner(); // Create an offline context with a sample rate that is very different from the sample rate // used in the OscillatorTestingUtils. This will create a internal PeriodicWave objects for // the Oscillator. This should not interfere with the oscillator test using a different // context with a different sample rate. - var context = new OfflineAudioContext(1, 1, 3000); - var osc = context.createOscillator(); - osc.type = "sawtooth"; - osc = null; + audit.define("test", (task, should) => { + let context0 = new OfflineAudioContext(1, 1, 3000); + let osc = context0.createOscillator(); + osc.type = "sawtooth"; + osc = null; - // This test is identical to the test in osc-sawtooth-sweep-snr.html. - var tester = OscillatorTestingUtils; + // This test is identical to the test in osc-sawtooth-sweep-snr.html. + let tester = OscillatorTestingUtils; - // The thresholds are experimentally determined. - tester.setThresholds({snr: 80.00, maxDiff: 4.06, diffCount: 15827}); - tester.runTest("sawtooth"); - successfullyParsed = true; + let context = new OfflineAudioContext(1, tester.sampleRate * + tester.lengthInSeconds, tester.sampleRate); + // The thresholds are experimentally determined. + tester.setThresholds({ + snr: 80.00, + maxDiff: 4.06, + diffCount: 15827 + }); + tester.runTest(context, "sawtooth", "Sawtooth PeriodicWave Test", + task, should); + }); + + audit.run(); </script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/resources/delay-testing.js b/third_party/WebKit/LayoutTests/webaudio/resources/delay-testing.js index 15f7c85..756abe3 100644 --- a/third_party/WebKit/LayoutTests/webaudio/resources/delay-testing.js +++ b/third_party/WebKit/LayoutTests/webaudio/resources/delay-testing.js
@@ -19,52 +19,50 @@ return audioBuffer; } -function checkDelayedResult(toneBuffer) { - return function(event) { - var renderedBuffer = event.renderedBuffer; +function checkDelayedResult(renderedBuffer, toneBuffer, should) { + var sourceData = toneBuffer.getChannelData(0); + var renderedData = renderedBuffer.getChannelData(0); - var sourceData = toneBuffer.getChannelData(0); - var renderedData = renderedBuffer.getChannelData(0); - - var delayTimeFrames = delayTimeSeconds * sampleRate; - var toneLengthFrames = toneLengthSeconds * sampleRate; + var delayTimeFrames = delayTimeSeconds * sampleRate; + var toneLengthFrames = toneLengthSeconds * sampleRate; - var success = true; - - var n = renderedBuffer.length; - - for (var i = 0; i < n; ++i) { - if (i < delayTimeFrames) { - // Check that initial portion is 0 (since signal is delayed). - if (renderedData[i] != 0) { - testFailed("Initial portion is not 0 at frame " + i); - success = false; - break; - } - } else if (i >= delayTimeFrames && i < delayTimeFrames + toneLengthFrames) { - // Make sure that the tone data is delayed by exactly the expected number of frames. - var j = i - delayTimeFrames; - if (renderedData[i] != sourceData[j]) { - testFailed("Actual data does not match expected data at frame " + i); - success = false; - break; - } - } else { - // Make sure we have silence after the delayed tone. - if (renderedData[i] != 0) { - testFailed("Final portion is not 0 at frame " + i); - success = false; - break; - } - } - } + var success = true; - if (success) { - testPassed("Test signal was correctly delayed by " + delayTimeSeconds + " sec."); + var n = renderedBuffer.length; + + for (var i = 0; i < n; ++i) { + if (i < delayTimeFrames) { + // Check that initial portion is 0 (since signal is delayed). + if (renderedData[i] != 0) { + should(renderedData[i], + "Initial portion expected to be 0 at frame " + i) + .beEqualTo(0); + success = false; + break; + } + } else if (i >= delayTimeFrames && i < delayTimeFrames + + toneLengthFrames) { + // Make sure that the tone data is delayed by exactly the expected number of frames. + var j = i - delayTimeFrames; + if (renderedData[i] != sourceData[j]) { + should(renderedData[i], + "Actual data at frame " + i) + .beEqualTo(sourceData[j]); + success = false; + break; + } } else { - testFailed("Test signal was not correctly delayed by " + delayTimeSeconds + " sec."); + // Make sure we have silence after the delayed tone. + if (renderedData[i] != 0) { + should(renderedData[j], + "Final portion at frame " + i) + .beEqualTo(0); + success = false; + break; + } } - - finishJSTest(); } + + should(success, "Delaying test signal by " + delayTimeSeconds + " sec was done") + .message("correctly", "incorrectly") }
diff --git a/third_party/WebKit/LayoutTests/webaudio/resources/oscillator-testing.js b/third_party/WebKit/LayoutTests/webaudio/resources/oscillator-testing.js index 49b376b..d4e2ec0 100644 --- a/third_party/WebKit/LayoutTests/webaudio/resources/oscillator-testing.js +++ b/third_party/WebKit/LayoutTests/webaudio/resources/oscillator-testing.js
@@ -67,9 +67,6 @@ // An AudioBuffer for the reference (expected) result. var reference = 0; -// The actual rendered data produced by the test. -var renderedData = 0; - // Signal power of the reference var signalPower = 0; @@ -109,22 +106,25 @@ return 10 * Math.log10(sPower / nPower); } -function loadReferenceAndRunTest(oscType) { - var bufferLoader = new BufferLoader( +function loadReferenceAndRunTest(context, oscType, task, should) { + var bufferLoader = new BufferLoader( context, [ "../Oscillator/oscillator-" + oscType + "-expected.wav" ], function (bufferList) { reference = bufferList[0].getChannelData(0); generateExponentialOscillatorSweep(context, oscType); - context.oncomplete = checkResult; + context.oncomplete = () => { + checkResult(event, should); + task.done(); + }; context.startRendering(); }); bufferLoader.load(); } -function checkResult (event) { - renderedData = event.renderedBuffer.getChannelData(0); +function checkResult (event, should) { + let renderedData = event.renderedBuffer.getChannelData(0); // Compute signal to noise ratio between the result and the reference. Also keep track // of the max difference (and position). @@ -148,30 +148,15 @@ } var snr = calculateSNR(signalPower, noisePower); - if (snr >= thresholdSNR) { - testPassed("Exceeded SNR threshold of " + thresholdSNR + " dB"); - } else { - testFailed("Expected SNR of " + thresholdSNR + " dB, but actual SNR is " + snr + " dB"); - } + should(snr, "SNR") + .beGreaterThanOrEqualTo(thresholdSNR); + should(maxError * waveScaleFactor, "Maximum difference in ulp (16-bits)") + .beLessThanOrEqualTo(thresholdDiff * waveScaleFactor); - if (maxError <= thresholdDiff) { - testPassed("Maximum difference below threshold of " - + (thresholdDiff * waveScaleFactor) + " ulp (16-bits)"); - } else { - testFailed("Maximum difference of " + (maxError * waveScaleFactor) + " at " - + errorPosition + " exceeded threshold of " + (thresholdDiff * waveScaleFactor) - + " ulp (16-bits)"); - } - - if (diffCount <= thresholdDiffCount) { - testPassed("Number of differences between actual and expected result is less than " + thresholdDiffCount - + " out of " + renderedData.length); - } else { - testFailed(diffCount + " differences found but expected no more than " + thresholdDiffCount - + " out of " + renderedData.length); - } - - finishJSTest(); + should(diffCount, + "Number of differences between actual and expected result out of " + + renderedData.length + " frames") + .beLessThanOrEqualTo(thresholdDiffCount); } function setThresholds(thresholds) { @@ -180,10 +165,8 @@ thresholdDiffCount = thresholds.diffCount; } -function runTest(oscType) { - window.jsTestIsAsync = true; - context = new OfflineAudioContext(1, sampleRate * lengthInSeconds, sampleRate); - loadReferenceAndRunTest(oscType); +function runTest(context, oscType, description, task, should) { + loadReferenceAndRunTest(context, oscType, task, should); } function createNewReference(oscType) { @@ -207,7 +190,6 @@ thresholdDiffCount: thresholdDiffCount, waveScaleFactor: waveScaleFactor, setThresholds: setThresholds, - loadReferenceAndRunTest: loadReferenceAndRunTest, runTest: runTest, createNewReference: createNewReference, };
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt index cf04b88..f8a9723 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -3720,6 +3720,7 @@ getter boundingClientRect getter intersectionRatio getter intersectionRect + getter isIntersecting getter rootBounds getter target getter time
diff --git a/third_party/WebKit/PerformanceTests/CSS/StyleSheetInsert-bootstrap.html b/third_party/WebKit/PerformanceTests/CSS/StyleSheetInsert-bootstrap.html index 1b0987cf..201f7f2c 100644 --- a/third_party/WebKit/PerformanceTests/CSS/StyleSheetInsert-bootstrap.html +++ b/third_party/WebKit/PerformanceTests/CSS/StyleSheetInsert-bootstrap.html
@@ -19,10 +19,10 @@ description: "Measures performance of inserting a style elemenet ocntaining bootstrap's CSS into an iframe.", run:function() { var testDoc = document.getElementsByTagName("iframe")[0].contentDocument; - testDoc.documentElement.innerHTML = ""; var style = testDoc.createElement("style"); style.textContent = styleText; testDoc.documentElement.appendChild(style); + testDoc.documentElement.removeChild(testDoc.documentElement.lastElementChild); } }); </script>
diff --git a/third_party/WebKit/Source/bindings/core/v8/DocumentWriteEvaluator.cpp b/third_party/WebKit/Source/bindings/core/v8/DocumentWriteEvaluator.cpp index 826a04f..cace623 100644 --- a/third_party/WebKit/Source/bindings/core/v8/DocumentWriteEvaluator.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/DocumentWriteEvaluator.cpp
@@ -8,7 +8,6 @@ #include "bindings/core/v8/V8BindingMacros.h" #include "bindings/core/v8/V8ScriptRunner.h" #include "core/frame/Location.h" -#include "core/html/parser/HTMLParserThread.h" #include "platform/instrumentation/tracing/TraceEvent.h" #include "wtf/text/StringUTF8Adaptor.h"
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseProperty.h b/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseProperty.h index eadab15..6c2c9c4d 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseProperty.h +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseProperty.h
@@ -8,6 +8,7 @@ #include "bindings/core/v8/ScriptPromise.h" #include "bindings/core/v8/ScriptPromisePropertyBase.h" #include "bindings/core/v8/ToV8.h" +#include "platform/ScriptForbiddenScope.h" #include "wtf/Noncopyable.h" #include "wtf/PassRefPtr.h" @@ -105,7 +106,7 @@ NOTREACHED(); return; } - DCHECK(!ScriptForbiddenScope::isScriptForbidden()); + CHECK(!ScriptForbiddenScope::isScriptForbidden()); if (!getExecutionContext() || getExecutionContext()->isContextDestroyed()) return; m_resolved = value;
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseResolver.h b/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseResolver.h index 2eb716d..fcb38a2 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseResolver.h +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptPromiseResolver.h
@@ -126,12 +126,19 @@ m_state = newState; ScriptState::Scope scope(m_scriptState.get()); - // TODO(aobzhirov): Converting value to the wrapper can trigger assert - // if the script is forbidden. - // The script check below will be unreachable in this case. - m_value.set(m_scriptState->isolate(), - ToV8(value, m_scriptState->context()->Global(), - m_scriptState->isolate())); + + // Calling ToV8 in a ScriptForbiddenScope will trigger a RELEASE_ASSERT and + // cause a crash. ToV8 just invokes a constructor for wrapper creation, + // which is safe (no author script can be run). Adding AllowUserAgentScript + // directly inside createWrapper could cause a perf impact (calling + // isMainThread() every time a wrapper is created is expensive). Ideally, + // resolveOrReject shouldn't be called inside a ScriptForbiddenScope. + { + ScriptForbiddenScope::AllowUserAgentScript allowScript; + m_value.set(m_scriptState->isolate(), + ToV8(value, m_scriptState->context()->Global(), + m_scriptState->isolate())); + } if (getExecutionContext()->isContextSuspended()) { // Retain this object until it is actually resolved or rejected.
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptStreamerThread.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptStreamerThread.cpp index aed61c4ab..6e003a40 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptStreamerThread.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptStreamerThread.cpp
@@ -30,24 +30,6 @@ s_sharedThread = new ScriptStreamerThread(); } -void ScriptStreamerThread::shutdown() { - ASSERT(s_sharedThread); - ScriptStreamerThread* toDelete; - { - MutexLocker locker(*s_mutex); - toDelete = s_sharedThread; - // The background thread can now safely check s_sharedThread; if it's - // not 0, we're not shutting down. - s_sharedThread = 0; - } - // This will run the pending tasks into completion. We shouldn't hold the - // mutex while doing that. - delete toDelete; - // Now it's safe to delete s_mutex, since there are no tasks that could - // access it later. - delete s_mutex; -} - ScriptStreamerThread* ScriptStreamerThread::shared() { return s_sharedThread; }
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptStreamerThread.h b/third_party/WebKit/Source/bindings/core/v8/ScriptStreamerThread.h index e54188a..531cc20 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptStreamerThread.h +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptStreamerThread.h
@@ -23,7 +23,6 @@ public: static void init(); - static void shutdown(); static ScriptStreamerThread* shared(); void postTask(std::unique_ptr<CrossThreadClosure>);
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp index edee432..4cc6e330 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
@@ -437,13 +437,6 @@ WTF::makeUnique<MainThreadDebugger>(isolate)); } -void V8Initializer::shutdownMainThread() { - ASSERT(isMainThread()); - v8::Isolate* isolate = V8PerIsolateData::mainThreadIsolate(); - V8PerIsolateData::willBeDestroyed(isolate); - V8PerIsolateData::destroy(isolate); -} - static void reportFatalErrorInWorker(const char* location, const char* message) { // FIXME: We temporarily deal with V8 internal error situations such as
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.h b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.h index 63680f1..0fea5842 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.h +++ b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.h
@@ -37,7 +37,6 @@ public: static void initializeMainThread(); - static void shutdownMainThread(); static void initializeWorker(v8::Isolate*); static void reportRejectedPromisesOnMainThread();
diff --git a/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.cpp b/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.cpp index 584f5181..558394c 100644 --- a/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.cpp
@@ -66,11 +66,6 @@ ~ExecutionState() { m_controller->m_executionState = m_outerState; } - DEFINE_INLINE_TRACE() { - visitor->trace(m_errorEventFromImportedScript); - visitor->trace(m_controller); - } - bool hadException; String errorMessage; std::unique_ptr<SourceLocation> m_location;
diff --git a/third_party/WebKit/Source/bindings/core/v8/custom/V8CustomEventCustom.cpp b/third_party/WebKit/Source/bindings/core/v8/custom/V8CustomEventCustom.cpp index 6f10be9..17470c1 100644 --- a/third_party/WebKit/Source/bindings/core/v8/custom/V8CustomEventCustom.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/custom/V8CustomEventCustom.cpp
@@ -107,6 +107,8 @@ const v8::FunctionCallbackInfo<v8::Value>& info, CustomEvent* impl) { ASSERT(info.Length() >= 3); + if (impl->isBeingDispatched()) + return; v8::Local<v8::Value> detail = info[3]; if (!detail.IsEmpty()) storeDetail(ScriptState::current(info.GetIsolate()), impl, info.Holder(),
diff --git a/third_party/WebKit/Source/bindings/templates/attributes.cpp.tmpl b/third_party/WebKit/Source/bindings/templates/attributes.cpp.tmpl index 8859c99..0eaa7f59 100644 --- a/third_party/WebKit/Source/bindings/templates/attributes.cpp.tmpl +++ b/third_party/WebKit/Source/bindings/templates/attributes.cpp.tmpl
@@ -43,15 +43,20 @@ {% endif %} {% if not attribute.is_static %} - {% if interface_name == 'Window' and not attribute.has_cross_origin_getter %} + {% set local_dom_window_only = interface_name == 'Window' and not attribute.has_cross_origin_getter %} + {% if local_dom_window_only %} + {% if attribute.is_check_security_for_receiver %} + {{cpp_class}}* uncheckedImpl = {{v8_class}}::toImpl(holder); + {% else %} // Same-origin attribute getters are never exposed via the cross-origin // interceptors. Since same-origin access requires a LocalDOMWindow, it is // safe to downcast here. LocalDOMWindow* impl = toLocalDOMWindow({{v8_class}}::toImpl(holder)); + {% endif %}{# attribute.is_check_security_for_receiver #} {% else %} {{cpp_class}}* impl = {{v8_class}}::toImpl(holder); - {% endif %} - {% endif %} + {% endif %}{# local_dom_window_only #} + {% endif %}{# not attribute.is_static #} {% if attribute.cached_attribute_validation_method %} // [CachedAttribute] @@ -68,10 +73,17 @@ {% if attribute.is_check_security_for_receiver and not attribute.is_data_type_property %} // Perform a security check for the receiver object. {{define_exception_state}} + {% if local_dom_window_only %} + if (!BindingSecurity::shouldAllowAccessTo(currentDOMWindow(info.GetIsolate()), uncheckedImpl, exceptionState)) { + {% else %} if (!BindingSecurity::shouldAllowAccessTo(currentDOMWindow(info.GetIsolate()), impl, exceptionState)) { + {% endif %}{# local_dom_window_only #} v8SetReturnValueNull(info); return; } + {% if local_dom_window_only %} + LocalDOMWindow* impl = toLocalDOMWindow(uncheckedImpl); + {% endif %}{# local_dom_window_only #} {% endif %} {% if attribute.is_check_security_for_return_value %} @@ -289,24 +301,36 @@ if (!impl) return; {% else %} - {% if interface_name == 'Window' and not attribute.has_cross_origin_setter %} - // Same-origin attribute setters are never exposed via the cross-origin + {% set local_dom_window_only = interface_name == 'Window' and not attribute.has_cross_origin_setter %} + {% if local_dom_window_only %} + {% if attribute.is_check_security_for_receiver %} + {{cpp_class}}* uncheckedImpl = {{v8_class}}::toImpl(holder); + {% else %} + // Same-origin attributes setters are never exposed via the cross-origin // interceptors. Since same-origin access requires a LocalDOMWindow, it is // safe to downcast here. LocalDOMWindow* impl = toLocalDOMWindow({{v8_class}}::toImpl(holder)); + {% endif %}{# attribute.is_check_security_for_receiver #} {% else %} {{cpp_class}}* impl = {{v8_class}}::toImpl(holder); - {% endif %} + {% endif %}{# local_dom_window_only #} {% endif %} {% endif %} {% if attribute.is_check_security_for_receiver and not attribute.is_data_type_property %} // Perform a security check for the receiver object. {{define_exception_state}} + {% if local_dom_window_only %} + if (!BindingSecurity::shouldAllowAccessTo(currentDOMWindow(info.GetIsolate()), uncheckedImpl, exceptionState)) { + {% else %} if (!BindingSecurity::shouldAllowAccessTo(currentDOMWindow(info.GetIsolate()), impl, exceptionState)) { + {% endif %}{# local_dom_window_only #} v8SetReturnValue(info, v8Value); return; } + {% if local_dom_window_only %} + LocalDOMWindow* impl = toLocalDOMWindow(uncheckedImpl); + {% endif %}{# local_dom_window_only #} {% endif %} {% if attribute.is_check_security_for_return_value %}
diff --git a/third_party/WebKit/Source/bindings/templates/methods.cpp.tmpl b/third_party/WebKit/Source/bindings/templates/methods.cpp.tmpl index 91b400d..a036d58 100644 --- a/third_party/WebKit/Source/bindings/templates/methods.cpp.tmpl +++ b/third_party/WebKit/Source/bindings/templates/methods.cpp.tmpl
@@ -29,15 +29,20 @@ return; } {% endif %} - {% if interface_name == 'Window' and not method.is_cross_origin %} + {% set local_dom_window_only = interface_name == 'Window' and not method.is_cross_origin %} + {% if local_dom_window_only %} + {% if method.is_check_security_for_receiver %} + {{cpp_class}}* uncheckedImpl = {{v8_class}}::toImpl(info.Holder()); + {% else %} // Same-origin methods are never exposed via the cross-origin interceptors. // Since same-origin access requires a LocalDOMWindow, it is safe to downcast // here. LocalDOMWindow* impl = toLocalDOMWindow({{v8_class}}::toImpl(info.Holder())); + {% endif %}{# method.is_check_security_for_receiver #} {% else %} {{cpp_class}}* impl = {{v8_class}}::toImpl(info.Holder()); - {% endif %} - {% endif %} + {% endif %}{# local_dom_window_only #} + {% endif %}{# not method.is_static #} {# Security checks #} {% if method.is_check_security_for_receiver %} @@ -53,11 +58,18 @@ } } {% else %}{# interface_name == 'EventTarget' #} + {% if local_dom_window_only %} + if (!BindingSecurity::shouldAllowAccessTo(currentDOMWindow(info.GetIsolate()), uncheckedImpl, exceptionState)) { + {% else %} if (!BindingSecurity::shouldAllowAccessTo(currentDOMWindow(info.GetIsolate()), impl, exceptionState)) { + {% endif %}{# local_dom_window_only #} return; } + {% if local_dom_window_only %} + LocalDOMWindow* impl = toLocalDOMWindow(uncheckedImpl); + {% endif %}{# local_dom_window_only #} {% endif %}{# interface_name == 'EventTarget' #} - {% endif %} + {% endif %}{# method.is_check_security_for_receiver #} {% if method.is_check_security_for_return_value %} {{define_exception_state}} if (!BindingSecurity::shouldAllowAccessTo(currentDOMWindow(info.GetIsolate()), {{method.cpp_value}}, exceptionState)) {
diff --git a/third_party/WebKit/Source/build/scripts/make_computed_style_base.py b/third_party/WebKit/Source/build/scripts/make_computed_style_base.py index 70fa6fe..2f2f84f 100755 --- a/third_party/WebKit/Source/build/scripts/make_computed_style_base.py +++ b/third_party/WebKit/Source/build/scripts/make_computed_style_base.py
@@ -87,6 +87,14 @@ enum_name = property_['type_name'] # From the Blink style guide: Enum members should use InterCaps with an initial capital letter. [names-enum-members] enum_values = [('k' + camel_case(k)) for k in property_['keywords']] + + if enum_name in enums: + # There's an enum with the same name, check if the enum values are the same + assert set(enums[enum_name]) == set(enum_values), \ + ("'" + property_['name'] + "' can't have type_name '" + enum_name + "' " + "because it was used by a previous property, but with a different set of keywords. " + "Either give it a different name or ensure the keywords are the same.") + enums[enum_name] = enum_values return enums
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn index 425812b5..b17a69f7 100644 --- a/third_party/WebKit/Source/core/BUILD.gn +++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -1135,7 +1135,6 @@ "html/parser/HTMLDocumentParserTest.cpp", "html/parser/HTMLEntityParserTest.cpp", "html/parser/HTMLParserIdiomsTest.cpp", - "html/parser/HTMLParserThreadTest.cpp", "html/parser/HTMLPreloadScannerTest.cpp", "html/parser/HTMLResourcePreloaderTest.cpp", "html/parser/HTMLSrcsetParserTest.cpp", @@ -1215,6 +1214,7 @@ "page/WindowFeaturesTest.cpp", "page/scrolling/ScrollStateTest.cpp", "page/scrolling/SnapCoordinatorTest.cpp", + "paint/BlockPaintInvalidatorTest.cpp", "paint/BoxPaintInvalidatorTest.cpp", "paint/FirstMeaningfulPaintDetectorTest.cpp", "paint/HTMLCanvasPainterTest.cpp",
diff --git a/third_party/WebKit/Source/core/CoreInitializer.cpp b/third_party/WebKit/Source/core/CoreInitializer.cpp index 6e73ba2..a094386 100644 --- a/third_party/WebKit/Source/core/CoreInitializer.cpp +++ b/third_party/WebKit/Source/core/CoreInitializer.cpp
@@ -51,7 +51,6 @@ #include "core/dom/StyleChangeReason.h" #include "core/events/EventFactory.h" #include "core/html/canvas/CanvasRenderingContextFactory.h" -#include "core/html/parser/HTMLParserThread.h" #include "core/workers/WorkerThread.h" #include "platform/FontFamilyNames.h" #include "platform/HTTPNames.h" @@ -60,6 +59,7 @@ #include "platform/weborigin/KURL.h" #include "platform/weborigin/SchemeRegistry.h" #include "platform/weborigin/SecurityPolicy.h" +#include "public/platform/Platform.h" #include "wtf/allocator/Partitions.h" #include "wtf/text/AtomicStringTable.h" @@ -144,14 +144,4 @@ ScriptStreamerThread::init(); } -void CoreInitializer::shutdown() { - // Shutdown V8-related background threads before V8 is ramped down. Note - // that this will wait the thread to stop its operations. - ScriptStreamerThread::shutdown(); - - ASSERT(Platform::current()); - - WorkerThread::terminateAndWaitForAllWorkers(); -} - } // namespace blink
diff --git a/third_party/WebKit/Source/core/CoreInitializer.h b/third_party/WebKit/Source/core/CoreInitializer.h index c691895..27dab231 100644 --- a/third_party/WebKit/Source/core/CoreInitializer.h +++ b/third_party/WebKit/Source/core/CoreInitializer.h
@@ -46,7 +46,6 @@ // Should be called by clients before trying to create Frames. virtual void initialize(); - virtual void shutdown(); protected: bool isInitialized() const { return m_isInitialized; }
diff --git a/third_party/WebKit/Source/core/animation/CSSInterpolationType.cpp b/third_party/WebKit/Source/core/animation/CSSInterpolationType.cpp index 2be30df5..861d27a5 100644 --- a/third_party/WebKit/Source/core/animation/CSSInterpolationType.cpp +++ b/third_party/WebKit/Source/core/animation/CSSInterpolationType.cpp
@@ -4,13 +4,14 @@ #include "core/animation/CSSInterpolationType.h" +#include <memory> #include "core/StylePropertyShorthand.h" #include "core/animation/StringKeyframe.h" #include "core/css/CSSCustomPropertyDeclaration.h" #include "core/css/CSSValue.h" #include "core/css/CSSVariableReferenceValue.h" #include "core/css/ComputedStyleCSSValueMapping.h" -#include "core/css/PropertyRegistry.h" +#include "core/css/PropertyRegistration.h" #include "core/css/parser/CSSTokenizer.h" #include "core/css/resolver/CSSVariableResolver.h" #include "core/css/resolver/StyleBuilder.h" @@ -18,7 +19,6 @@ #include "core/style/DataEquivalency.h" #include "platform/RuntimeEnabledFeatures.h" #include "wtf/PtrUtil.h" -#include <memory> namespace blink { @@ -107,6 +107,13 @@ DCHECK(!isShorthandProperty(cssProperty())); } +void CSSInterpolationType::setCustomPropertyRegistration( + const PropertyRegistration& registration) { + DCHECK(getProperty().isCSSCustomProperty()); + DCHECK(!m_registration); + m_registration = ®istration; +} + InterpolationValue CSSInterpolationType::maybeConvertSingle( const PropertySpecificKeyframe& keyframe, const InterpolationEnvironment& environment, @@ -164,15 +171,6 @@ return maybeConvertValue(*value, &state, conversionCheckers); } -const PropertyRegistration* getRegistration(const StyleResolverState& state, - const AtomicString& propertyName) { - const PropertyRegistry* registry = state.document().propertyRegistry(); - if (registry) { - return registry->registration(propertyName); - } - return nullptr; -} - InterpolationValue CSSInterpolationType::maybeConvertCustomPropertyDeclaration( const CSSCustomPropertyDeclaration& declaration, const StyleResolverState& state, @@ -198,30 +196,29 @@ const AtomicString& name = declaration.name(); DCHECK_EQ(getProperty().customPropertyName(), name); - const PropertyRegistration* registration = getRegistration(state, name); - if (!declaration.value()) { // Unregistered custom properties inherit: // https://www.w3.org/TR/css-variables-1/#defining-variables - bool isInheritedProperty = registration ? registration->inherits() : true; + bool isInheritedProperty = + m_registration ? m_registration->inherits() : true; DCHECK(declaration.isInitial(isInheritedProperty) || declaration.isInherit(isInheritedProperty)); - if (!registration) { + if (!m_registration) { return nullptr; } const CSSValue* value = nullptr; if (declaration.isInitial(isInheritedProperty)) { - value = registration->initial(); + value = m_registration->initial(); } else { value = state.parentStyle()->getRegisteredVariable(name, isInheritedProperty); if (!value) { - value = registration->initial(); + value = m_registration->initial(); } conversionCheckers.push_back(InheritedCustomPropertyChecker::create( - name, isInheritedProperty, value, registration->initial())); + name, isInheritedProperty, value, m_registration->initial())); } if (!value) { return nullptr; @@ -240,9 +237,9 @@ return nullptr; } - if (registration) { + if (m_registration) { const CSSValue* parsedValue = - declaration.value()->parseForSyntax(registration->syntax()); + declaration.value()->parseForSyntax(m_registration->syntax()); if (parsedValue) { return maybeConvertValue(*parsedValue, &state, conversionCheckers); } @@ -253,21 +250,20 @@ InterpolationValue CSSInterpolationType::maybeConvertUnderlyingValue( const InterpolationEnvironment& environment) const { - const StyleResolverState& state = environment.state(); + const ComputedStyle& style = environment.style(); if (!getProperty().isCSSCustomProperty()) { - return maybeConvertStandardPropertyUnderlyingValue(*state.style()); + return maybeConvertStandardPropertyUnderlyingValue(style); } const PropertyHandle property = getProperty(); const AtomicString& name = property.customPropertyName(); - const PropertyRegistration* registration = getRegistration(state, name); - if (!registration) { + if (!m_registration) { return nullptr; } const CSSValue* underlyingValue = - state.style()->getRegisteredVariable(name, registration->inherits()); + style.getRegisteredVariable(name, m_registration->inherits()); if (!underlyingValue) { - underlyingValue = registration->initial(); + underlyingValue = m_registration->initial(); } if (!underlyingValue) { return nullptr; @@ -313,10 +309,8 @@ ComputedStyle& style = *state.style(); const PropertyHandle property = getProperty(); const AtomicString& propertyName = property.customPropertyName(); - const PropertyRegistration* registration = - getRegistration(state, propertyName); - DCHECK(registration); - if (registration->inherits()) { + DCHECK(m_registration); + if (m_registration->inherits()) { style.setResolvedInheritedVariable(propertyName, variableData.release(), cssValue); } else {
diff --git a/third_party/WebKit/Source/core/animation/CSSInterpolationType.h b/third_party/WebKit/Source/core/animation/CSSInterpolationType.h index 3628fd6..2c9b9ee 100644 --- a/third_party/WebKit/Source/core/animation/CSSInterpolationType.h +++ b/third_party/WebKit/Source/core/animation/CSSInterpolationType.h
@@ -11,8 +11,12 @@ namespace blink { class CSSCustomPropertyDeclaration; +class PropertyRegistration; class CSSInterpolationType : public InterpolationType { + public: + void setCustomPropertyRegistration(const PropertyRegistration&); + protected: CSSInterpolationType(PropertyHandle); @@ -75,6 +79,8 @@ void applyCustomPropertyValue(const InterpolableValue&, const NonInterpolableValue*, StyleResolverState&) const; + + WeakPersistent<const PropertyRegistration> m_registration; }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.cpp b/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.cpp index e4c3603..e77d94e 100644 --- a/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.cpp +++ b/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.cpp
@@ -4,6 +4,7 @@ #include "core/animation/CSSInterpolationTypesMap.h" +#include <memory> #include "core/animation/CSSBasicShapeInterpolationType.h" #include "core/animation/CSSBorderImageLengthBoxInterpolationType.h" #include "core/animation/CSSClipInterpolationType.h" @@ -34,9 +35,9 @@ #include "core/animation/CSSValueInterpolationType.h" #include "core/animation/CSSVisibilityInterpolationType.h" #include "core/css/CSSPropertyMetadata.h" +#include "core/css/CSSSyntaxDescriptor.h" #include "core/css/PropertyRegistry.h" #include "wtf/PtrUtil.h" -#include <memory> namespace blink { @@ -325,4 +326,49 @@ return m_registry ? m_registry->registrationCount() : 0; } +CSSInterpolationTypes +CSSInterpolationTypesMap::createCSSInterpolationTypesForSyntax( + const AtomicString& propertyName, + const CSSSyntaxDescriptor& descriptor) { + PropertyHandle property(propertyName); + CSSInterpolationTypes result; + for (const CSSSyntaxComponent& component : descriptor.components()) { + if (component.m_repeatable) { + // TODO(alancutter): Support animation of repeatable types. + continue; + } + + switch (component.m_type) { + case CSSSyntaxType::Color: + result.push_back(WTF::makeUnique<CSSColorInterpolationType>(property)); + break; + case CSSSyntaxType::Length: + result.push_back(WTF::makeUnique<CSSLengthInterpolationType>(property)); + break; + case CSSSyntaxType::Number: + case CSSSyntaxType::Percentage: + case CSSSyntaxType::LengthPercentage: + case CSSSyntaxType::Image: + case CSSSyntaxType::Url: + case CSSSyntaxType::Integer: + case CSSSyntaxType::Angle: + case CSSSyntaxType::Time: + case CSSSyntaxType::Resolution: + case CSSSyntaxType::TransformFunction: + // TODO(alancutter): Support smooth interpolation of these types. + break; + case CSSSyntaxType::TokenStream: + case CSSSyntaxType::Ident: + case CSSSyntaxType::CustomIdent: + // Uses the CSSValueInterpolationType added below. + break; + default: + NOTREACHED(); + break; + } + } + result.push_back(WTF::makeUnique<CSSValueInterpolationType>(property)); + return result; +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.h b/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.h index 88561ce..7a90cbd 100644 --- a/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.h +++ b/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.h
@@ -5,13 +5,17 @@ #ifndef CSSInterpolationTypesMap_h #define CSSInterpolationTypesMap_h +#include "core/animation/CSSInterpolationType.h" #include "core/animation/InterpolationTypesMap.h" #include "platform/heap/Handle.h" namespace blink { +class CSSSyntaxDescriptor; class PropertyRegistry; +using CSSInterpolationTypes = Vector<std::unique_ptr<CSSInterpolationType>>; + class CSSInterpolationTypesMap : public InterpolationTypesMap { public: CSSInterpolationTypesMap(const PropertyRegistry* registry) @@ -20,6 +24,10 @@ const InterpolationTypes& get(const PropertyHandle&) const final; size_t version() const final; + static CSSInterpolationTypes createCSSInterpolationTypesForSyntax( + const AtomicString& propertyName, + const CSSSyntaxDescriptor&); + private: Member<const PropertyRegistry> m_registry; };
diff --git a/third_party/WebKit/Source/core/animation/InterpolationEnvironment.h b/third_party/WebKit/Source/core/animation/InterpolationEnvironment.h index 61d76ad..313793ed 100644 --- a/third_party/WebKit/Source/core/animation/InterpolationEnvironment.h +++ b/third_party/WebKit/Source/core/animation/InterpolationEnvironment.h
@@ -6,12 +6,13 @@ #define InterpolationEnvironment_h #include "core/animation/InterpolationTypesMap.h" +#include "core/css/resolver/StyleResolverState.h" #include "platform/heap/Handle.h" #include "wtf/Allocator.h" namespace blink { -class StyleResolverState; +class ComputedStyle; class SVGPropertyBase; class SVGElement; @@ -21,16 +22,16 @@ public: explicit InterpolationEnvironment(const InterpolationTypesMap& map, StyleResolverState& state) - : m_interpolationTypesMap(map), - m_state(&state), - m_svgElement(nullptr), - m_svgBaseValue(nullptr) {} + : m_interpolationTypesMap(map), m_state(&state), m_style(state.style()) {} + + explicit InterpolationEnvironment(const InterpolationTypesMap& map, + const ComputedStyle& style) + : m_interpolationTypesMap(map), m_style(&style) {} explicit InterpolationEnvironment(const InterpolationTypesMap& map, SVGElement& svgElement, const SVGPropertyBase& svgBaseValue) : m_interpolationTypesMap(map), - m_state(nullptr), m_svgElement(&svgElement), m_svgBaseValue(&svgBaseValue) {} @@ -47,6 +48,11 @@ return *m_state; } + const ComputedStyle& style() const { + DCHECK(m_style); + return *m_style; + } + SVGElement& svgElement() { DCHECK(m_svgElement); return *m_svgElement; @@ -63,9 +69,14 @@ private: const InterpolationTypesMap& m_interpolationTypesMap; - StyleResolverState* m_state; - Member<SVGElement> m_svgElement; - Member<const SVGPropertyBase> m_svgBaseValue; + + // CSSInterpolationType environment + StyleResolverState* m_state = nullptr; + const ComputedStyle* m_style = nullptr; + + // SVGInterpolationType environment + Member<SVGElement> m_svgElement = nullptr; + Member<const SVGPropertyBase> m_svgBaseValue = nullptr; }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.cpp b/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.cpp index e6358b8..4f763f0 100644 --- a/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.cpp +++ b/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.cpp
@@ -618,11 +618,8 @@ style.translate(), style.effectiveZoom(), initialTranslate); } case CSSPropertyRotate: { - DEFINE_STATIC_REF(RotateTransformOperation, initialRotate, - RotateTransformOperation::create( - 0, 0, 1, 0, TransformOperation::Rotate3D)); - return createFromTransformProperties( - style.rotate(), style.effectiveZoom(), initialRotate); + return createFromTransformProperties(style.rotate(), + style.effectiveZoom(), nullptr); } case CSSPropertyScale: { return createFromTransformProperties(style.scale(), style.effectiveZoom(),
diff --git a/third_party/WebKit/Source/core/clipboard/DataObject.cpp b/third_party/WebKit/Source/core/clipboard/DataObject.cpp index 87c4687c..11b7d9d 100644 --- a/third_party/WebKit/Source/core/clipboard/DataObject.cpp +++ b/third_party/WebKit/Source/core/clipboard/DataObject.cpp
@@ -222,10 +222,12 @@ File::createForUserProvidedFile(filename, displayName), fileSystemId)); } -void DataObject::addSharedBuffer(const String& name, - PassRefPtr<SharedBuffer> buffer) { - internalAddFileItem( - DataObjectItem::createFromSharedBuffer(name, std::move(buffer))); +void DataObject::addSharedBuffer(PassRefPtr<SharedBuffer> buffer, + const KURL& sourceURL, + const String& filenameExtension, + const AtomicString& contentDisposition) { + internalAddFileItem(DataObjectItem::createFromSharedBuffer( + std::move(buffer), sourceURL, filenameExtension, contentDisposition)); } DataObject::DataObject() : m_modifiers(0) {} @@ -322,10 +324,15 @@ item.storageType = WebDragData::Item::StorageTypeString; item.stringType = originalItem->type(); item.stringData = originalItem->getAsString(); + item.title = originalItem->title(); + item.baseURL = originalItem->baseURL(); } else if (originalItem->kind() == DataObjectItem::FileKind) { if (originalItem->sharedBuffer()) { item.storageType = WebDragData::Item::StorageTypeBinaryData; item.binaryData = originalItem->sharedBuffer(); + item.binaryDataSourceURL = originalItem->baseURL(); + item.binaryDataFilenameExtension = originalItem->filenameExtension(); + item.binaryDataContentDisposition = originalItem->title(); } else if (originalItem->isFilename()) { Blob* blob = originalItem->getAsFile(); if (blob->isFile()) { @@ -355,8 +362,6 @@ } else { ASSERT_NOT_REACHED(); } - item.title = originalItem->title(); - item.baseURL = originalItem->baseURL(); itemList[i] = item; } data.swapItems(itemList);
diff --git a/third_party/WebKit/Source/core/clipboard/DataObject.h b/third_party/WebKit/Source/core/clipboard/DataObject.h index 9cd3e3d3..bcb9b03b 100644 --- a/third_party/WebKit/Source/core/clipboard/DataObject.h +++ b/third_party/WebKit/Source/core/clipboard/DataObject.h
@@ -103,7 +103,10 @@ } // Used to handle files (images) being dragged out. - void addSharedBuffer(const String& name, PassRefPtr<SharedBuffer>); + void addSharedBuffer(PassRefPtr<SharedBuffer>, + const KURL&, + const String& filenameExtension, + const AtomicString& contentDisposition); int modifiers() const { return m_modifiers; } void setModifiers(int modifiers) { m_modifiers = modifiers; }
diff --git a/third_party/WebKit/Source/core/clipboard/DataObjectItem.cpp b/third_party/WebKit/Source/core/clipboard/DataObjectItem.cpp index 1b1acde..a2c985c 100644 --- a/third_party/WebKit/Source/core/clipboard/DataObjectItem.cpp +++ b/third_party/WebKit/Source/core/clipboard/DataObjectItem.cpp
@@ -33,6 +33,7 @@ #include "core/clipboard/Pasteboard.h" #include "core/fileapi/Blob.h" #include "platform/clipboard/ClipboardMimeTypes.h" +#include "platform/network/mime/MIMETypeRegistry.h" #include "public/platform/Platform.h" #include "public/platform/WebClipboard.h" @@ -77,11 +78,18 @@ } DataObjectItem* DataObjectItem::createFromSharedBuffer( - const String& name, - PassRefPtr<SharedBuffer> buffer) { - DataObjectItem* item = new DataObjectItem(FileKind, String()); + PassRefPtr<SharedBuffer> buffer, + const KURL& sourceURL, + const String& filenameExtension, + const AtomicString& contentDisposition) { + DataObjectItem* item = new DataObjectItem( + FileKind, + MIMETypeRegistry::getWellKnownMIMETypeForExtension(filenameExtension)); item->m_sharedBuffer = buffer; - item->m_title = name; + item->m_filenameExtension = filenameExtension; + // TODO(dcheng): Rename these fields to be more generically named. + item->m_title = contentDisposition; + item->m_baseURL = sourceURL; return item; }
diff --git a/third_party/WebKit/Source/core/clipboard/DataObjectItem.h b/third_party/WebKit/Source/core/clipboard/DataObjectItem.h index 350aa61..4e48dcd 100644 --- a/third_party/WebKit/Source/core/clipboard/DataObjectItem.h +++ b/third_party/WebKit/Source/core/clipboard/DataObjectItem.h
@@ -56,8 +56,11 @@ static DataObjectItem* createFromURL(const String& url, const String& title); static DataObjectItem* createFromHTML(const String& html, const KURL& baseURL); - static DataObjectItem* createFromSharedBuffer(const String& filename, - PassRefPtr<SharedBuffer>); + static DataObjectItem* createFromSharedBuffer( + PassRefPtr<SharedBuffer>, + const KURL&, + const String& fileExtension, + const AtomicString& contentDisposition); static DataObjectItem* createFromPasteboard(const String& type, uint64_t sequenceNumber); @@ -69,6 +72,7 @@ // Used to support legacy DataTransfer APIs and renderer->browser // serialization. PassRefPtr<SharedBuffer> sharedBuffer() const { return m_sharedBuffer; } + String filenameExtension() const { return m_filenameExtension; } String title() const { return m_title; } KURL baseURL() const { return m_baseURL; } bool isFilename() const; @@ -95,6 +99,7 @@ Member<File> m_file; RefPtr<SharedBuffer> m_sharedBuffer; // Optional metadata. Currently used for URL, HTML, and dragging files in. + String m_filenameExtension; String m_title; KURL m_baseURL;
diff --git a/third_party/WebKit/Source/core/clipboard/DataTransfer.cpp b/third_party/WebKit/Source/core/clipboard/DataTransfer.cpp index a4305db05..168520b 100644 --- a/third_party/WebKit/Source/core/clipboard/DataTransfer.cpp +++ b/third_party/WebKit/Source/core/clipboard/DataTransfer.cpp
@@ -270,7 +270,7 @@ static void writeImageToDataObject(DataObject* dataObject, Element* element, - const KURL& url) { + const KURL& imageURL) { // Shove image data into a DataObject for use as a file ImageResourceContent* cachedImage = getImageResourceContent(element); if (!cachedImage || !cachedImage->getImage() || !cachedImage->isLoaded()) @@ -280,54 +280,23 @@ if (!imageBuffer || !imageBuffer->size()) return; - String imageExtension = cachedImage->getImage()->filenameExtension(); - ASSERT(!imageExtension.isEmpty()); - - // Determine the filename for the file contents of the image. - String filename = cachedImage->response().suggestedFilename(); - if (filename.isEmpty()) - filename = url.lastPathComponent(); - - String fileExtension; - if (filename.isEmpty()) { - filename = element->getAttribute(HTMLNames::altAttr); - } else { - // Strip any existing extension. Assume that alt text is usually not a - // filename. - int extensionIndex = filename.reverseFind('.'); - if (extensionIndex != -1) { - fileExtension = filename.substring(extensionIndex + 1); - filename.truncate(extensionIndex); - } - } - - if (!fileExtension.isEmpty() && fileExtension != imageExtension) { - String imageMimeType = - MIMETypeRegistry::getMIMETypeForExtension(imageExtension); - ASSERT(imageMimeType.startsWith("image/")); - // Use the file extension only if it has imageMimeType: it's untrustworthy - // otherwise. - if (imageMimeType == - MIMETypeRegistry::getMIMETypeForExtension(fileExtension)) - imageExtension = fileExtension; - } - - imageExtension = "." + imageExtension; - validateFilename(filename, imageExtension); - - dataObject->addSharedBuffer(filename + imageExtension, imageBuffer); + dataObject->addSharedBuffer(imageBuffer, imageURL, + cachedImage->getImage()->filenameExtension(), + cachedImage->response().httpHeaderFields().get( + HTTPNames::Content_Disposition)); } void DataTransfer::declareAndWriteDragImage(Element* element, - const KURL& url, + const KURL& linkURL, + const KURL& imageURL, const String& title) { if (!m_dataObject) return; - m_dataObject->setURLAndTitle(url, title); + m_dataObject->setURLAndTitle(linkURL.isValid() ? linkURL : imageURL, title); // Write the bytes in the image to the file format. - writeImageToDataObject(m_dataObject.get(), element, url); + writeImageToDataObject(m_dataObject.get(), element, imageURL); // Put img tag on the clipboard referencing the image m_dataObject->setData(mimeTypeTextHTML,
diff --git a/third_party/WebKit/Source/core/clipboard/DataTransfer.h b/third_party/WebKit/Source/core/clipboard/DataTransfer.h index 658dffd..8e80137 100644 --- a/third_party/WebKit/Source/core/clipboard/DataTransfer.h +++ b/third_party/WebKit/Source/core/clipboard/DataTransfer.h
@@ -98,7 +98,10 @@ std::unique_ptr<DragImage> createDragImage(IntPoint& dragLocation, LocalFrame*) const; - void declareAndWriteDragImage(Element*, const KURL&, const String& title); + void declareAndWriteDragImage(Element*, + const KURL& linkURL, + const KURL& imageURL, + const String& title); void writeURL(Node*, const KURL&, const String&); void writeSelection(const FrameSelection&);
diff --git a/third_party/WebKit/Source/core/css/CSSStyleSheet.cpp b/third_party/WebKit/Source/core/css/CSSStyleSheet.cpp index 44201915..c7ddcfa 100644 --- a/third_party/WebKit/Source/core/css/CSSStyleSheet.cpp +++ b/third_party/WebKit/Source/core/css/CSSStyleSheet.cpp
@@ -160,7 +160,14 @@ DCHECK(m_contents->isMutable()); DCHECK_LE(m_contents->clientSize(), 1u); - didMutate(); + Document* owner = ownerDocument(); + if (!owner) + return; + if (ownerNode() && ownerNode()->isConnected()) { + owner->styleEngine().setNeedsActiveStyleUpdate(ownerNode()->treeScope()); + if (StyleResolver* resolver = owner->styleEngine().resolver()) + resolver->invalidateMatchedPropertiesCache(); + } } void CSSStyleSheet::didMutate() {
diff --git a/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.cpp b/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.cpp index bdff583..d401711e 100644 --- a/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.cpp +++ b/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.cpp
@@ -214,50 +214,4 @@ isAnimationTainted); } -InterpolationTypes CSSSyntaxDescriptor::createInterpolationTypes( - const AtomicString& propertyName) const { - PropertyHandle property(propertyName); - InterpolationTypes interpolationTypes; - for (const CSSSyntaxComponent& component : m_syntaxComponents) { - if (component.m_repeatable) { - // TODO(alancutter): Support animation of repeatable types. - continue; - } - - switch (component.m_type) { - case CSSSyntaxType::Color: - interpolationTypes.push_back( - WTF::makeUnique<CSSColorInterpolationType>(property)); - break; - case CSSSyntaxType::Length: - interpolationTypes.push_back( - WTF::makeUnique<CSSLengthInterpolationType>(property)); - break; - case CSSSyntaxType::Number: - case CSSSyntaxType::Percentage: - case CSSSyntaxType::LengthPercentage: - case CSSSyntaxType::Image: - case CSSSyntaxType::Url: - case CSSSyntaxType::Integer: - case CSSSyntaxType::Angle: - case CSSSyntaxType::Time: - case CSSSyntaxType::Resolution: - case CSSSyntaxType::TransformFunction: - // TODO(alancutter): Support smooth interpolation of these types. - break; - case CSSSyntaxType::TokenStream: - case CSSSyntaxType::Ident: - case CSSSyntaxType::CustomIdent: - // Uses the CSSValueInterpolationType added below. - break; - default: - NOTREACHED(); - break; - } - } - interpolationTypes.push_back( - WTF::makeUnique<CSSValueInterpolationType>(property)); - return interpolationTypes; -} - } // namespace blink
diff --git a/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.h b/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.h index ff4dace..75e8939 100644 --- a/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.h +++ b/third_party/WebKit/Source/core/css/CSSSyntaxDescriptor.h
@@ -5,7 +5,6 @@ #ifndef CSSSyntaxDescriptor_h #define CSSSyntaxDescriptor_h -#include "core/animation/InterpolationTypesMap.h" #include "core/css/parser/CSSParserTokenRange.h" namespace blink { @@ -52,9 +51,9 @@ return m_syntaxComponents.size() == 1 && m_syntaxComponents[0].m_type == CSSSyntaxType::TokenStream; } - - InterpolationTypes createInterpolationTypes( - const AtomicString& propertyName) const; + const Vector<CSSSyntaxComponent>& components() const { + return m_syntaxComponents; + } private: Vector<CSSSyntaxComponent> m_syntaxComponents;
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp index 1c2ba0d3..db6eb1b9 100644 --- a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp +++ b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
@@ -3570,8 +3570,7 @@ } case CSSPropertyRotate: { if (!style.rotate()) - return CSSPrimitiveValue::create(0, - CSSPrimitiveValue::UnitType::Degrees); + return CSSIdentifierValue::create(CSSValueNone); CSSValueList* list = CSSValueList::createSpaceSeparated(); if (style.rotate()->x() != 0 || style.rotate()->y() != 0 ||
diff --git a/third_party/WebKit/Source/core/css/ElementRuleCollector.cpp b/third_party/WebKit/Source/core/css/ElementRuleCollector.cpp index 22d131e79..3be2f2c 100644 --- a/third_party/WebKit/Source/core/css/ElementRuleCollector.cpp +++ b/third_party/WebKit/Source/core/css/ElementRuleCollector.cpp
@@ -340,7 +340,7 @@ m_style->setHasPseudoStyle(dynamicPseudo); } else { if (m_style && ruleData.containsUncommonAttributeSelector()) - m_style->setUnique(); + m_style->setUnique(true); m_matchedRules.push_back( MatchedRule(&ruleData, result.specificity, cascadeOrder,
diff --git a/third_party/WebKit/Source/core/css/PropertyRegistration.cpp b/third_party/WebKit/Source/core/css/PropertyRegistration.cpp index 2d049f6..ff078f3 100644 --- a/third_party/WebKit/Source/core/css/PropertyRegistration.cpp +++ b/third_party/WebKit/Source/core/css/PropertyRegistration.cpp
@@ -4,6 +4,7 @@ #include "core/css/PropertyRegistration.h" +#include "core/animation/CSSInterpolationTypesMap.h" #include "core/css/CSSStyleSheet.h" #include "core/css/CSSSyntaxDescriptor.h" #include "core/css/CSSValueList.h" @@ -21,6 +22,31 @@ namespace blink { +static InterpolationTypes setRegistrationOnCSSInterpolationTypes( + CSSInterpolationTypes cssInterpolationTypes, + const PropertyRegistration& registration) { + InterpolationTypes result; + for (auto& cssInterpolationType : cssInterpolationTypes) { + cssInterpolationType->setCustomPropertyRegistration(registration); + result.push_back(std::move(cssInterpolationType)); + } + return result; +} + +PropertyRegistration::PropertyRegistration( + const CSSSyntaxDescriptor& syntax, + bool inherits, + const CSSValue* initial, + PassRefPtr<CSSVariableData> initialVariableData, + CSSInterpolationTypes cssInterpolationTypes) + : m_syntax(syntax), + m_inherits(inherits), + m_initial(initial), + m_initialVariableData(initialVariableData), + m_interpolationTypes(setRegistrationOnCSSInterpolationTypes( + std::move(cssInterpolationTypes), + *this)) {} + static bool computationallyIndependent(const CSSValue& value) { DCHECK(!value.isCSSWideKeyword()); @@ -93,8 +119,9 @@ return; } - InterpolationTypes interpolationTypes = - syntaxDescriptor.createInterpolationTypes(atomicName); + CSSInterpolationTypes cssInterpolationTypes = + CSSInterpolationTypesMap::createCSSInterpolationTypesForSyntax( + atomicName, syntaxDescriptor); if (descriptor.hasInitialValue()) { CSSTokenizer tokenizer(descriptor.initialValue()); @@ -121,7 +148,7 @@ tokenizer.tokenRange(), isAnimationTainted, false); registry.registerProperty( atomicName, syntaxDescriptor, descriptor.inherits(), initial, - std::move(initialVariableData), std::move(interpolationTypes)); + std::move(initialVariableData), std::move(cssInterpolationTypes)); } else { if (!syntaxDescriptor.isTokenStream()) { exceptionState.throwDOMException( @@ -131,7 +158,7 @@ } registry.registerProperty(atomicName, syntaxDescriptor, descriptor.inherits(), nullptr, nullptr, - std::move(interpolationTypes)); + std::move(cssInterpolationTypes)); } // TODO(timloh): Invalidate only elements with this custom property set
diff --git a/third_party/WebKit/Source/core/css/PropertyRegistration.h b/third_party/WebKit/Source/core/css/PropertyRegistration.h index c4b28da..0626c8c 100644 --- a/third_party/WebKit/Source/core/css/PropertyRegistration.h +++ b/third_party/WebKit/Source/core/css/PropertyRegistration.h
@@ -5,7 +5,7 @@ #ifndef PropertyRegistration_h #define PropertyRegistration_h -#include "core/animation/InterpolationType.h" +#include "core/animation/CSSInterpolationType.h" #include "core/animation/InterpolationTypesMap.h" #include "core/css/CSSSyntaxDescriptor.h" #include "core/css/CSSValue.h" @@ -20,6 +20,8 @@ class PropertyDescriptor; class ScriptState; +using CSSInterpolationTypes = Vector<std::unique_ptr<CSSInterpolationType>>; + class PropertyRegistration : public GarbageCollectedFinalized<PropertyRegistration> { public: @@ -27,16 +29,11 @@ const PropertyDescriptor&, ExceptionState&); - PropertyRegistration(const CSSSyntaxDescriptor& syntax, + PropertyRegistration(const CSSSyntaxDescriptor&, bool inherits, const CSSValue* initial, PassRefPtr<CSSVariableData> initialVariableData, - InterpolationTypes interpolationTypes) - : m_syntax(syntax), - m_inherits(inherits), - m_initial(initial), - m_initialVariableData(initialVariableData), - m_interpolationTypes(std::move(interpolationTypes)) {} + CSSInterpolationTypes); const CSSSyntaxDescriptor& syntax() const { return m_syntax; } bool inherits() const { return m_inherits; }
diff --git a/third_party/WebKit/Source/core/css/PropertyRegistry.cpp b/third_party/WebKit/Source/core/css/PropertyRegistry.cpp index 7bb0153..478893a 100644 --- a/third_party/WebKit/Source/core/css/PropertyRegistry.cpp +++ b/third_party/WebKit/Source/core/css/PropertyRegistry.cpp
@@ -12,12 +12,12 @@ bool inherits, const CSSValue* initial, PassRefPtr<CSSVariableData> initialVariableData, - InterpolationTypes interpolationTypes) { + CSSInterpolationTypes cssInterpolationTypes) { DCHECK(!registration(name)); - m_registrations.set(name, - new PropertyRegistration(syntax, inherits, initial, - std::move(initialVariableData), - std::move(interpolationTypes))); + m_registrations.set( + name, new PropertyRegistration(syntax, inherits, initial, + std::move(initialVariableData), + std::move(cssInterpolationTypes))); } const PropertyRegistration* PropertyRegistry::registration(
diff --git a/third_party/WebKit/Source/core/css/PropertyRegistry.h b/third_party/WebKit/Source/core/css/PropertyRegistry.h index 0bb3a0d..78b80e2 100644 --- a/third_party/WebKit/Source/core/css/PropertyRegistry.h +++ b/third_party/WebKit/Source/core/css/PropertyRegistry.h
@@ -20,7 +20,7 @@ bool inherits, const CSSValue* initial, PassRefPtr<CSSVariableData> initialVariableData, - InterpolationTypes); + CSSInterpolationTypes); const PropertyRegistration* registration(const AtomicString&) const; size_t registrationCount() const { return m_registrations.size(); }
diff --git a/third_party/WebKit/Source/core/css/SelectorChecker.cpp b/third_party/WebKit/Source/core/css/SelectorChecker.cpp index da7b0ec..e6327380 100644 --- a/third_party/WebKit/Source/core/css/SelectorChecker.cpp +++ b/third_party/WebKit/Source/core/css/SelectorChecker.cpp
@@ -884,7 +884,7 @@ if (context.inRightmostCompound) { m_elementStyle->setAffectedByDrag(); } else { - m_elementStyle->setUnique(); + m_elementStyle->setUnique(true); element.setChildrenOrSiblingsAffectedByDrag(); } } @@ -896,7 +896,7 @@ if (context.inRightmostCompound) { m_elementStyle->setAffectedByFocus(); } else { - m_elementStyle->setUnique(); + m_elementStyle->setUnique(true); element.setChildrenOrSiblingsAffectedByFocus(); } } @@ -908,7 +908,7 @@ if (context.inRightmostCompound) { m_elementStyle->setAffectedByHover(); } else { - m_elementStyle->setUnique(); + m_elementStyle->setUnique(true); element.setChildrenOrSiblingsAffectedByHover(); } } @@ -925,7 +925,7 @@ if (context.inRightmostCompound) { m_elementStyle->setAffectedByActive(); } else { - m_elementStyle->setUnique(); + m_elementStyle->setUnique(true); element.setChildrenOrSiblingsAffectedByActive(); } }
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIRotate.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIRotate.cpp index 081aaa7a..03b87bdb 100644 --- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIRotate.cpp +++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIRotate.cpp
@@ -4,6 +4,7 @@ #include "core/css/properties/CSSPropertyAPIRotate.h" +#include "core/CSSValueKeywords.h" #include "core/css/CSSValueList.h" #include "core/css/parser/CSSPropertyParserHelpers.h" #include "platform/RuntimeEnabledFeatures.h" @@ -14,6 +15,11 @@ CSSParserTokenRange& range, const CSSParserContext* context) { DCHECK(RuntimeEnabledFeatures::cssIndependentTransformPropertiesEnabled()); + + CSSValueID id = range.peek().id(); + if (id == CSSValueNone) + return CSSPropertyParserHelpers::consumeIdent(range); + CSSValueList* list = CSSValueList::createSpaceSeparated(); for (unsigned i = 0; i < 3; i++) { // 3 dimensions of rotation
diff --git a/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp b/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp index 4eec65b..6ccb2d97 100644 --- a/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp +++ b/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp
@@ -333,8 +333,4 @@ m_nonInheritedVariables(state.style()->nonInheritedVariables()), m_registry(state.document().propertyRegistry()) {} -DEFINE_TRACE(CSSVariableResolver) { - visitor->trace(m_registry); -} - } // namespace blink
diff --git a/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.h b/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.h index 3c35e667..d42a189c 100644 --- a/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.h +++ b/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.h
@@ -37,8 +37,6 @@ static void computeRegisteredVariables(const StyleResolverState&); - DECLARE_TRACE(); - private: CSSVariableResolver(const StyleResolverState&);
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp b/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp index a261919..015eb7e 100644 --- a/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp +++ b/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp
@@ -458,7 +458,7 @@ // share this style. if (style.hasPseudoStyle(PseudoIdFirstLetter) || style.transitions() || style.animations()) - style.setUnique(); + style.setUnique(true); adjustStyleForEditing(style);
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp index 16a2d9d..8462cb6 100644 --- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp +++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
@@ -1287,6 +1287,11 @@ } Rotation StyleBuilderConverter::convertRotation(const CSSValue& value) { + if (value.isIdentifierValue()) { + DCHECK_EQ(toCSSIdentifierValue(value).getValueID(), CSSValueNone); + return Rotation(FloatPoint3D(0, 0, 1), 0); + } + const CSSValueList& list = toCSSValueList(value); ASSERT(list.length() == 1 || list.length() == 4); double x = 0; @@ -1305,6 +1310,11 @@ PassRefPtr<RotateTransformOperation> StyleBuilderConverter::convertRotate( StyleResolverState& state, const CSSValue& value) { + if (value.isIdentifierValue()) { + DCHECK_EQ(toCSSIdentifierValue(value).getValueID(), CSSValueNone); + return nullptr; + } + return RotateTransformOperation::create(convertRotation(value), TransformOperation::Rotate3D); }
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp b/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp index a3a30d32..ba5f4f2 100644 --- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp +++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
@@ -794,9 +794,9 @@ DCHECK_EQ(functionValue->functionType(), CSSValueAttr); // FIXME: Can a namespace be specified for an attr(foo)? if (state.style()->styleType() == PseudoIdNone) - state.style()->setUnique(); + state.style()->setUnique(true); else - state.parentStyle()->setUnique(); + state.parentStyle()->setUnique(true); QualifiedName attr( nullAtom, toCSSCustomIdentValue(functionValue->item(0)).value(), nullAtom);
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp index 7f86007..56c31fe 100644 --- a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp +++ b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
@@ -736,7 +736,7 @@ // computation of font-relative lengths. state.style()->setTextAutosizingMultiplier( element->computedStyle()->textAutosizingMultiplier()); - state.style()->setUnique(); + state.style()->setUnique(true); } if (state.hasDirAutoAttribute())
diff --git a/third_party/WebKit/Source/core/dom/CharacterData.cpp b/third_party/WebKit/Source/core/dom/CharacterData.cpp index 47bd7ca..22c3fd2 100644 --- a/third_party/WebKit/Source/core/dom/CharacterData.cpp +++ b/third_party/WebKit/Source/core/dom/CharacterData.cpp
@@ -42,9 +42,6 @@ void CharacterData::setData(const String& data) { const String& nonNullData = !data.isNull() ? data : emptyString; - if (m_data == nonNullData) - return; - unsigned oldLength = length(); setDataAndUpdate(nonNullData, 0, oldLength, nonNullData.length(), @@ -176,9 +173,6 @@ unsigned oldLength, unsigned newLength, UpdateSource source) { - if (source != UpdateFromParser) - document().dataWillChange(*this); - String oldData = m_data; m_data = newData;
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.cpp b/third_party/WebKit/Source/core/dom/ContainerNode.cpp index f5c16a1..207659d 100644 --- a/third_party/WebKit/Source/core/dom/ContainerNode.cpp +++ b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
@@ -266,6 +266,8 @@ Node* ContainerNode::insertBefore(Node* newChild, Node* refChild, ExceptionState& exceptionState) { + // https://dom.spec.whatwg.org/#concept-node-pre-insert + // insertBefore(node, 0) is equivalent to appendChild(node) if (!refChild) return appendChild(newChild, exceptionState); @@ -284,9 +286,12 @@ return nullptr; } - // Nothing to do. - if (refChild->previousSibling() == newChild || refChild == newChild) - return newChild; + // 3. If reference child is node, set it to node’s next sibling. + if (refChild == newChild) { + refChild = newChild->nextSibling(); + if (!refChild) + return appendChild(newChild, exceptionState); + } NodeVector targets; if (!collectChildrenAndRemoveFromOldParentWithCheck( @@ -391,8 +396,7 @@ Node* ContainerNode::replaceChild(Node* newChild, Node* oldChild, ExceptionState& exceptionState) { - if (oldChild == newChild) // Nothing to do. - return oldChild; + // https://dom.spec.whatwg.org/#concept-node-replace if (!oldChild) { exceptionState.throwDOMException(NotFoundError, @@ -412,17 +416,23 @@ } ChildListMutationScope mutation(*this); + // 7. Let reference child be child’s next sibling. Node* next = oldChild->nextSibling(); + // 8. If reference child is node, set it to node’s next sibling. + if (next == newChild) + next = newChild->nextSibling(); - // Remove the node we're replacing. + // TODO(tkent): According to the specification, we should remove |newChild| + // from its parent here, and create a separated mutation record for it. + // Refer to imported/wpt/dom/nodes/MutationObserver-childList.html. + + // 12. If child’s parent is not null, run these substeps: + // 1. Set removedNodes to a list solely containing child. + // 2. Remove child from its parent with the suppress observers flag set. removeChild(oldChild, exceptionState); if (exceptionState.hadException()) return nullptr; - if (next && (next->previousSibling() == newChild || - next == newChild)) // nothing to do - return oldChild; - // Does this one more time because removeChild() fires a MutationEvent. if (!checkAcceptChild(newChild, oldChild, exceptionState)) return oldChild; @@ -649,9 +659,6 @@ return newChild; DCHECK(newChild); - if (newChild == m_lastChild) // nothing to do - return newChild; - NodeVector targets; if (!collectChildrenAndRemoveFromOldParentWithCheck( nullptr, nullptr, *newChild, targets, exceptionState))
diff --git a/third_party/WebKit/Source/core/dom/DOMURLUtils.cpp b/third_party/WebKit/Source/core/dom/DOMURLUtils.cpp index 853ff19..2062b74 100644 --- a/third_party/WebKit/Source/core/dom/DOMURLUtils.cpp +++ b/third_party/WebKit/Source/core/dom/DOMURLUtils.cpp
@@ -123,10 +123,10 @@ // FIXME: have KURL do this clearing of the query component // instead, if practical. Will require addressing // http://crbug.com/108690, for one. - if (value[0] == '?') - kurl.setQuery(value.length() == 1 ? String() : value.substring(1)); + if ((value.length() == 1 && value[0] == '?') || value.isEmpty()) + kurl.setQuery(String()); else - kurl.setQuery(value.isEmpty() ? String() : value); + kurl.setQuery(value); setURL(kurl); }
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp index 8a48c7bbd..cc8eabd 100644 --- a/third_party/WebKit/Source/core/dom/Document.cpp +++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -4249,11 +4249,6 @@ styleEngine().elementWillBeRemoved(toElement(n)); } -void Document::dataWillChange(const CharacterData& characterData) { - if (LocalFrame* frame = this->frame()) - frame->selection().dataWillChange(characterData); -} - void Document::didInsertText(Node* text, unsigned offset, unsigned length) { for (Range* range : m_ranges) range->didInsertText(text, offset, length);
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h index fcfb3ff..0ed30f7 100644 --- a/third_party/WebKit/Source/core/dom/Document.h +++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -81,7 +81,6 @@ class CDATASection; class CSSStyleSheet; class CanvasFontCache; -class CharacterData; class ChromeClient; class CompositorPendingAnimations; class Comment; @@ -752,8 +751,6 @@ void nodeChildrenWillBeRemoved(ContainerNode&); // nodeWillBeRemoved is only safe when removing one node at a time. void nodeWillBeRemoved(Node&); - // Called just before a destructive update to some CharacterData. - void dataWillChange(const CharacterData&); bool canAcceptChild(const Node& newChild, const Node* oldChild, ExceptionState&) const;
diff --git a/third_party/WebKit/Source/core/dom/Fullscreen.cpp b/third_party/WebKit/Source/core/dom/Fullscreen.cpp index 4868177..7d3ee205 100644 --- a/third_party/WebKit/Source/core/dom/Fullscreen.cpp +++ b/third_party/WebKit/Source/core/dom/Fullscreen.cpp
@@ -481,6 +481,10 @@ // 5. Return, and run the remaining steps asynchronously. // 6. Optionally, perform some animation. + if (from(document).m_pendingFullscreenElement) { + UseCounter::count(document, + UseCounter::FullscreenRequestWithPendingElement); + } from(document).m_pendingFullscreenElement = &element; document.frame()->chromeClient().enterFullscreen(*document.frame());
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObservation.cpp b/third_party/WebKit/Source/core/dom/IntersectionObservation.cpp index e8e8030..e1471030 100644 --- a/third_party/WebKit/Source/core/dom/IntersectionObservation.cpp +++ b/third_party/WebKit/Source/core/dom/IntersectionObservation.cpp
@@ -75,7 +75,7 @@ m_shouldReportRootBounds ? &snappedRootBounds : nullptr; IntersectionObserverEntry* newEntry = new IntersectionObserverEntry( timestamp, newVisibleRatio, geometry.targetIntRect(), rootBoundsPointer, - geometry.intersectionIntRect(), target()); + geometry.intersectionIntRect(), geometry.doesIntersect(), target()); observer()->enqueueIntersectionObserverEntry(*newEntry); setLastThresholdIndex(newThresholdIndex); }
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp b/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp index 779e0a3..85dc348 100644 --- a/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp +++ b/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp
@@ -306,6 +306,7 @@ for (auto& observation : m_observations) observation->disconnect(); m_observations.clear(); + m_entries.clear(); } HeapVector<Member<IntersectionObserverEntry>> IntersectionObserver::takeRecords(
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.cpp b/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.cpp index 9f01a4ea..1cb9427c 100644 --- a/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.cpp +++ b/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.cpp
@@ -14,13 +14,15 @@ const IntRect& boundingClientRect, const IntRect* rootBounds, const IntRect& intersectionRect, + bool isIntersecting, Element* target) : m_time(time), m_intersectionRatio(intersectionRatio), m_boundingClientRect(ClientRect::create(boundingClientRect)), m_rootBounds(rootBounds ? ClientRect::create(*rootBounds) : nullptr), m_intersectionRect(ClientRect::create(intersectionRect)), - m_target(target) + m_target(target), + m_isIntersecting(isIntersecting) {}
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.h b/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.h index db853a9..da1e1841 100644 --- a/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.h +++ b/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.h
@@ -26,6 +26,7 @@ const IntRect& boundingClientRect, const IntRect* rootBounds, const IntRect& intersectionRect, + bool isIntersecting, Element*); double time() const { return m_time; } @@ -33,6 +34,7 @@ ClientRect* boundingClientRect() const { return m_boundingClientRect; } ClientRect* rootBounds() const { return m_rootBounds; } ClientRect* intersectionRect() const { return m_intersectionRect; } + bool isIntersecting() const { return m_isIntersecting; } Element* target() const { return m_target.get(); } DECLARE_VIRTUAL_TRACE(); @@ -44,6 +46,7 @@ Member<ClientRect> m_rootBounds; Member<ClientRect> m_intersectionRect; Member<Element> m_target; + bool m_isIntersecting; }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.idl b/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.idl index 5cfe284..034031f1 100644 --- a/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.idl +++ b/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.idl
@@ -14,6 +14,7 @@ readonly attribute ClientRect? rootBounds; readonly attribute ClientRect boundingClientRect; readonly attribute ClientRect intersectionRect; + readonly attribute boolean isIntersecting; readonly attribute double intersectionRatio; readonly attribute Element target; };
diff --git a/third_party/WebKit/Source/core/dom/MutationObserver.idl b/third_party/WebKit/Source/core/dom/MutationObserver.idl index cb930d0..53231f7 100644 --- a/third_party/WebKit/Source/core/dom/MutationObserver.idl +++ b/third_party/WebKit/Source/core/dom/MutationObserver.idl
@@ -34,7 +34,7 @@ CustomConstructor(MutationCallback callback), DependentLifetime, ] interface MutationObserver { - [RaisesException] void observe(Node target, MutationObserverInit options); + [RaisesException] void observe(Node target, optional MutationObserverInit options); void disconnect(); sequence<MutationRecord> takeRecords(); };
diff --git a/third_party/WebKit/Source/core/dom/QualifiedName.cpp b/third_party/WebKit/Source/core/dom/QualifiedName.cpp index 6e93039e..28e2584 100644 --- a/third_party/WebKit/Source/core/dom/QualifiedName.cpp +++ b/third_party/WebKit/Source/core/dom/QualifiedName.cpp
@@ -109,8 +109,8 @@ } // Global init routines -DEFINE_GLOBAL(QualifiedName, anyName, nullAtom, starAtom, starAtom); -DEFINE_GLOBAL(QualifiedName, nullName, nullAtom, nullAtom, nullAtom); +DEFINE_GLOBAL(QualifiedName, anyName); +DEFINE_GLOBAL(QualifiedName, nullName); void QualifiedName::initAndReserveCapacityForSize(unsigned size) { DCHECK(starAtom.impl());
diff --git a/third_party/WebKit/Source/core/dom/Range.cpp b/third_party/WebKit/Source/core/dom/Range.cpp index fcc2400..3187a1e9 100644 --- a/third_party/WebKit/Source/core/dom/Range.cpp +++ b/third_party/WebKit/Source/core/dom/Range.cpp
@@ -917,11 +917,15 @@ } container = m_start.container(); - container->insertBefore( - newNode, NodeTraversal::childAt(*container, m_start.offset()), - exceptionState); - if (exceptionState.hadException()) - return; + Node* referenceNode = NodeTraversal::childAt(*container, m_start.offset()); + // TODO(tkent): The following check must be unnecessary if we follow the + // algorithm defined in the specification. + // https://dom.spec.whatwg.org/#concept-range-insert + if (newNode != referenceNode) { + container->insertBefore(newNode, referenceNode, exceptionState); + if (exceptionState.hadException()) + return; + } // Note that m_start.offset() may have changed as a result of // container->insertBefore, when the node we are inserting comes before the
diff --git a/third_party/WebKit/Source/core/dom/StyleEngineTest.cpp b/third_party/WebKit/Source/core/dom/StyleEngineTest.cpp index 41b7f8b..e62026e 100644 --- a/third_party/WebKit/Source/core/dom/StyleEngineTest.cpp +++ b/third_party/WebKit/Source/core/dom/StyleEngineTest.cpp
@@ -4,6 +4,9 @@ #include "core/dom/StyleEngine.h" +#include "core/css/CSSRuleList.h" +#include "core/css/CSSStyleRule.h" +#include "core/css/CSSStyleSheet.h" #include "core/css/StyleSheetContents.h" #include "core/css/parser/CSSParserContext.h" #include "core/dom/Document.h" @@ -373,4 +376,46 @@ t1->computedStyle()->visitedDependentColor(CSSPropertyColor)); } +TEST_F(StyleEngineTest, ModifyStyleRuleMatchedPropertiesCache) { + // Test that the MatchedPropertiesCache is cleared when a StyleRule is + // modified. The MatchedPropertiesCache caches results based on + // StylePropertySet pointers. When a mutable StylePropertySet is modified, + // the pointer doesn't change, yet the declarations do. + + document().body()->setInnerHTML( + "<style id='s1'>#t1 { color: blue }</style>" + "<div id='t1'>Green</div>"); + document().view()->updateAllLifecyclePhases(); + + Element* t1 = document().getElementById("t1"); + ASSERT_TRUE(t1); + ASSERT_TRUE(t1->computedStyle()); + EXPECT_EQ(makeRGB(0, 0, 255), + t1->computedStyle()->visitedDependentColor(CSSPropertyColor)); + + CSSStyleSheet* sheet = toCSSStyleSheet(document().styleSheets().item(0)); + ASSERT_TRUE(sheet); + ASSERT_TRUE(sheet->cssRules()); + CSSStyleRule* styleRule = toCSSStyleRule(sheet->cssRules()->item(0)); + ASSERT_TRUE(styleRule); + ASSERT_TRUE(styleRule->style()); + + // Modify the StylePropertySet once to make it a mutable set. Subsequent + // modifications will not change the StylePropertySet pointer and cache hash + // value will be the same. + styleRule->style()->setProperty("color", "red", "", ASSERT_NO_EXCEPTION); + document().view()->updateAllLifecyclePhases(); + + ASSERT_TRUE(t1->computedStyle()); + EXPECT_EQ(makeRGB(255, 0, 0), + t1->computedStyle()->visitedDependentColor(CSSPropertyColor)); + + styleRule->style()->setProperty("color", "green", "", ASSERT_NO_EXCEPTION); + document().view()->updateAllLifecyclePhases(); + + ASSERT_TRUE(t1->computedStyle()); + EXPECT_EQ(makeRGB(0, 128, 0), + t1->computedStyle()->visitedDependentColor(CSSPropertyColor)); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/CaretDisplayItemClient.cpp b/third_party/WebKit/Source/core/editing/CaretDisplayItemClient.cpp index 88ef35c..cbd1bef 100644 --- a/third_party/WebKit/Source/core/editing/CaretDisplayItemClient.cpp +++ b/third_party/WebKit/Source/core/editing/CaretDisplayItemClient.cpp
@@ -34,10 +34,11 @@ #include "core/layout/api/LayoutBlockItem.h" #include "core/layout/api/LayoutItem.h" #include "core/layout/api/LayoutViewItem.h" +#include "core/paint/ObjectPaintInvalidator.h" #include "core/paint/PaintInfo.h" +#include "core/paint/PaintInvalidator.h" #include "core/paint/PaintLayer.h" #include "platform/graphics/GraphicsContext.h" -#include "platform/graphics/GraphicsLayer.h" #include "platform/graphics/paint/DrawingRecorder.h" namespace blink { @@ -45,11 +46,11 @@ CaretDisplayItemClient::CaretDisplayItemClient() = default; CaretDisplayItemClient::~CaretDisplayItemClient() = default; -static inline bool caretRendersInsideNode(Node* node) { +static inline bool caretRendersInsideNode(const Node* node) { return node && !isDisplayInsideTable(node) && !editingIgnoresContent(*node); } -LayoutBlock* CaretDisplayItemClient::caretLayoutObject(Node* node) { +LayoutBlock* CaretDisplayItemClient::caretLayoutBlock(const Node* node) { if (!node) return nullptr; @@ -107,54 +108,136 @@ // Get the layoutObject that will be responsible for painting the caret // (which is either the layoutObject we just found, or one of its containers). LayoutBlockItem caretPainterItem = - LayoutBlockItem(caretLayoutObject(caretPosition.anchorNode())); - + LayoutBlockItem(caretLayoutBlock(caretPosition.anchorNode())); + LayoutRect caretLocalRectWithWritingMode = caretLocalRect; + caretPainterItem.flipForWritingMode(caretLocalRectWithWritingMode); return mapCaretRectToCaretPainter(LayoutItem(layoutObject), caretPainterItem, - caretLocalRect); + caretLocalRectWithWritingMode); } -// TODO(yoichio): |node| is FrameSelection::m_previousCaretNode and this is bad -// design. We should use only previous layoutObject or Rectangle to invalidate -// old caret. -void CaretDisplayItemClient::invalidateLocalCaretRect(Node* node, - const LayoutRect& rect) { - LayoutBlock* caretLayoutBlock = caretLayoutObject(node); - if (!caretLayoutBlock) +void CaretDisplayItemClient::updateStyleAndLayoutIfNeeded( + const PositionWithAffinity& caretPosition) { + LayoutBlock* newLayoutBlock = caretLayoutBlock(caretPosition.anchorNode()); + if (newLayoutBlock != m_layoutBlock) { + if (m_layoutBlock) + m_layoutBlock->setMayNeedPaintInvalidation(); + m_previousLayoutBlock = m_layoutBlock; + m_layoutBlock = newLayoutBlock; + m_needsPaintInvalidation = true; + } else { + m_previousLayoutBlock = nullptr; + } + + if (!newLayoutBlock) { + m_color = Color(); + m_localRect = LayoutRect(); + return; + } + + Color newColor; + if (caretPosition.anchorNode()) { + newColor = caretPosition.anchorNode()->layoutObject()->resolveColor( + CSSPropertyCaretColor); + } + if (newColor != m_color) { + m_needsPaintInvalidation = true; + m_color = newColor; + } + + LayoutRect newLocalRect = computeCaretRect(caretPosition); + if (newLocalRect != m_localRect) { + m_needsPaintInvalidation = true; + m_localRect = newLocalRect; + } + + if (m_needsPaintInvalidation) + newLayoutBlock->setMayNeedPaintInvalidation(); +} + +void CaretDisplayItemClient::invalidatePaintIfNeeded( + const LayoutBlock& block, + const PaintInvalidatorContext& context, + PaintInvalidationReason layoutBlockPaintInvalidationReason) { + if (block == m_previousLayoutBlock) { + // Invalidate the previous caret if it was in a different block. + // m_previousLayoutBlock is set only when it's different from m_layoutBlock. + DCHECK(block != m_layoutBlock); + + ObjectPaintInvalidatorWithContext objectInvalidator(*m_previousLayoutBlock, + context); + if (!isImmediateFullPaintInvalidationReason( + layoutBlockPaintInvalidationReason)) { + objectInvalidator.fullyInvalidatePaint(PaintInvalidationCaret, + m_visualRect, LayoutRect()); + } + + // If m_layoutBlock is not null, the following will be done when + // the new caret is invalidated in m_layoutBlock. + if (!m_layoutBlock) { + context.paintingLayer->setNeedsRepaint(); + objectInvalidator.invalidateDisplayItemClient(*this, + PaintInvalidationCaret); + m_visualRect = LayoutRect(); + m_needsPaintInvalidation = false; + } + + m_previousLayoutBlock = nullptr; + return; + } + + if (block != m_layoutBlock) return; - // FIXME: Need to over-paint 1 pixel to workaround some rounding problems. - // https://bugs.webkit.org/show_bug.cgi?id=108283 - LayoutRect inflatedRect = rect; - inflatedRect.inflate(LayoutUnit(1)); + // Invalidate the new caret, and the old caret if it was in the same block. + LayoutRect newVisualRect; + if (m_layoutBlock && !m_localRect.isEmpty()) { + newVisualRect = m_localRect; + context.mapLocalRectToPaintInvalidationBacking(*m_layoutBlock, + newVisualRect); + newVisualRect.move(m_layoutBlock->scrollAdjustmentForPaintInvalidation( + *context.paintInvalidationContainer)); - // FIXME: We should not allow paint invalidation out of paint invalidation - // state. crbug.com/457415 - DisablePaintInvalidationStateAsserts disabler; + if (m_layoutBlock->usesCompositedScrolling()) { + // The caret should use scrolling coordinate space. + DCHECK(m_layoutBlock == context.paintInvalidationContainer); + newVisualRect.move(LayoutSize(m_layoutBlock->scrolledContentOffset())); + } + } - m_visualRect = - node->layoutObject()->invalidatePaintRectangle(inflatedRect, this); + if (m_needsPaintInvalidation || newVisualRect != m_visualRect) { + m_needsPaintInvalidation = false; + + ObjectPaintInvalidatorWithContext objectInvalidator(*m_layoutBlock, + context); + if (!isImmediateFullPaintInvalidationReason( + layoutBlockPaintInvalidationReason)) { + objectInvalidator.fullyInvalidatePaint(PaintInvalidationCaret, + m_visualRect, newVisualRect); + } + + context.paintingLayer->setNeedsRepaint(); + objectInvalidator.invalidateDisplayItemClient(*this, + PaintInvalidationCaret); + } + + m_visualRect = newVisualRect; } -void CaretDisplayItemClient::paintCaret(Node* node, - GraphicsContext& context, - const LayoutRect& caretLocalRect, - const LayoutPoint& paintOffset, - DisplayItem::Type displayItemType) { +void CaretDisplayItemClient::paintCaret( + GraphicsContext& context, + const LayoutPoint& paintOffset, + DisplayItem::Type displayItemType) const { if (DrawingRecorder::useCachedDrawingIfPossible(context, *this, displayItemType)) return; - LayoutRect drawingRect = caretLocalRect; - if (LayoutBlock* layoutObject = caretLayoutObject(node)) - layoutObject->flipForWritingMode(drawingRect); + LayoutRect drawingRect = m_localRect; drawingRect.moveBy(paintOffset); - const Color caretColor = - node->layoutObject()->resolveColor(CSSPropertyCaretColor); IntRect paintRect = pixelSnappedIntRect(drawingRect); DrawingRecorder drawingRecorder(context, *this, DisplayItem::kCaret, paintRect); - context.fillRect(paintRect, caretColor); + context.fillRect(paintRect, m_color); } String CaretDisplayItemClient::debugName() const {
diff --git a/third_party/WebKit/Source/core/editing/CaretDisplayItemClient.h b/third_party/WebKit/Source/core/editing/CaretDisplayItemClient.h index 042a3e5..2c740f5 100644 --- a/third_party/WebKit/Source/core/editing/CaretDisplayItemClient.h +++ b/third_party/WebKit/Source/core/editing/CaretDisplayItemClient.h
@@ -37,6 +37,7 @@ class GraphicsContext; class LayoutBlock; +struct PaintInvalidatorContext; class CaretDisplayItemClient final : public DisplayItemClient { WTF_MAKE_NONCOPYABLE(CaretDisplayItemClient); @@ -45,26 +46,65 @@ CaretDisplayItemClient(); virtual ~CaretDisplayItemClient(); + // TODO(yosin,wangxianzhu): Make these two static functions private or + // combine them into updateForPaintInvalidation() when the callsites in + // FrameCaret are removed. + // Creating VisiblePosition causes synchronous layout so we should use the // PositionWithAffinity version if possible. // A position in HTMLTextFromControlElement is a typical example. static LayoutRect computeCaretRect(const PositionWithAffinity& caretPosition); + static LayoutBlock* caretLayoutBlock(const Node*); - void paintCaret(Node*, - GraphicsContext&, - const LayoutRect& caretLocalRect, - const LayoutPoint&, - DisplayItem::Type); + // Called indirectly from LayoutObject::clearPreviousVisualRects(). + void clearPreviousVisualRect(const LayoutBlock& block) { + if (shouldPaintCaret(block)) + m_visualRect = LayoutRect(); + } - static LayoutBlock* caretLayoutObject(Node*); - void invalidateLocalCaretRect(Node*, const LayoutRect&); + void layoutBlockWillBeDestroyed(const LayoutBlock& block) { + if (!shouldPaintCaret(block)) + return; + m_visualRect = LayoutRect(); + m_layoutBlock = nullptr; + } + + // Called when a FrameView finishes layout. Updates style and geometry of the + // caret for paint invalidation and painting. + void updateStyleAndLayoutIfNeeded(const PositionWithAffinity& caretPosition); + + // Called during LayoutBlock paint invalidation. + void invalidatePaintIfNeeded( + const LayoutBlock&, + const PaintInvalidatorContext&, + PaintInvalidationReason layoutBlockPaintInvalidationReason); + + bool shouldPaintCaret(const LayoutBlock& block) const { + return &block == m_layoutBlock; + } + void paintCaret(GraphicsContext&, + const LayoutPoint& paintOffset, + DisplayItem::Type) const; // DisplayItemClient methods. LayoutRect visualRect() const final; String debugName() const final; private: + // These are updated by updateStyleAndLayoutIfNeeded(). + Color m_color; + LayoutRect m_localRect; + LayoutBlock* m_layoutBlock = nullptr; + + // This is set to the previous m_layoutBlock if m_layoutLayout will change + // during updateStyleAndLayoutIfNeeded() and can be used in + // invalidatePaintIfNeeded() only. + const LayoutBlock* m_previousLayoutBlock = nullptr; + + // This is updated by invalidatePaintIfNeeded(). LayoutRect m_visualRect; + + bool m_needsPaintInvalidation = false; }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/DragCaret.cpp b/third_party/WebKit/Source/core/editing/DragCaret.cpp index dbf4fe99..9a9a4b4 100644 --- a/third_party/WebKit/Source/core/editing/DragCaret.cpp +++ b/third_party/WebKit/Source/core/editing/DragCaret.cpp
@@ -25,6 +25,7 @@ #include "core/editing/DragCaret.h" +#include "core/editing/CaretDisplayItemClient.h" #include "core/editing/EditingUtilities.h" #include "core/frame/Settings.h" #include "core/layout/api/LayoutViewItem.h" @@ -40,52 +41,40 @@ return new DragCaret; } -bool DragCaret::hasCaretIn(const LayoutBlock& layoutBlock) const { - Node* node = m_position.anchorNode(); - if (!node) - return false; - if (layoutBlock != CaretDisplayItemClient::caretLayoutObject(node)) - return false; - return rootEditableElementOf(m_position.position()); +void DragCaret::clearPreviousVisualRect(const LayoutBlock& block) { + m_caretBase->clearPreviousVisualRect(block); +} + +void DragCaret::layoutBlockWillBeDestroyed(const LayoutBlock& block) { + m_caretBase->layoutBlockWillBeDestroyed(block); +} + +void DragCaret::updateStyleAndLayoutIfNeeded() { + m_caretBase->updateStyleAndLayoutIfNeeded( + rootEditableElementOf(m_position.position()) ? m_position + : PositionWithAffinity()); +} + +void DragCaret::invalidatePaintIfNeeded(const LayoutBlock& block, + const PaintInvalidatorContext& context, + PaintInvalidationReason reason) { + m_caretBase->invalidatePaintIfNeeded(block, context, reason); } bool DragCaret::isContentRichlyEditable() const { return isRichlyEditablePosition(m_position.position()); } -void DragCaret::invalidateCaretRect(Node* node, - const LayoutRect& caretLocalRect) { - // TODO(editing-dev): The use of updateStyleAndLayout - // needs to be audited. See http://crbug.com/590369 for more details. - // In the long term we should use idle time spell checker to prevent - // synchronous layout caused by spell checking (see crbug.com/517298). - node->document().updateStyleAndLayoutTree(); - if (!hasEditableStyle(*node)) - return; - m_caretBase->invalidateLocalCaretRect(node, caretLocalRect); -} - void DragCaret::setCaretPosition(const PositionWithAffinity& position) { - // for querying Layer::compositingState() - // This code is probably correct, since it doesn't occur in a stack that - // involves updating compositing state. - DisableCompositingQueryAsserts disabler; - - if (Node* node = m_position.anchorNode()) - invalidateCaretRect(node, m_caretLocalRect); m_position = createVisiblePosition(position).toPositionWithAffinity(); Document* document = nullptr; if (Node* node = m_position.anchorNode()) { - invalidateCaretRect(node, m_caretLocalRect); document = &node->document(); setContext(document); } - if (m_position.isNull()) { - m_caretLocalRect = LayoutRect(); - } else { + if (!m_position.isNull()) { DCHECK(!m_position.isOrphan()); document->updateStyleAndLayoutTree(); - m_caretLocalRect = CaretDisplayItemClient::computeCaretRect(m_position); } } @@ -118,13 +107,15 @@ SynchronousMutationObserver::trace(visitor); } -void DragCaret::paintDragCaret(LocalFrame* frame, +bool DragCaret::shouldPaintCaret(const LayoutBlock& block) const { + return m_caretBase->shouldPaintCaret(block); +} + +void DragCaret::paintDragCaret(const LocalFrame* frame, GraphicsContext& context, const LayoutPoint& paintOffset) const { - if (m_position.anchorNode()->document().frame() == frame) { - m_caretBase->paintCaret(m_position.anchorNode(), context, m_caretLocalRect, - paintOffset, DisplayItem::kDragCaret); - } + if (m_position.anchorNode()->document().frame() == frame) + m_caretBase->paintCaret(context, paintOffset, DisplayItem::kDragCaret); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/DragCaret.h b/third_party/WebKit/Source/core/editing/DragCaret.h index a4a5597..5a06890c 100644 --- a/third_party/WebKit/Source/core/editing/DragCaret.h +++ b/third_party/WebKit/Source/core/editing/DragCaret.h
@@ -27,12 +27,16 @@ #ifndef DragCaret_h #define DragCaret_h +#include <memory> #include "core/dom/SynchronousMutationObserver.h" #include "core/editing/CaretDisplayItemClient.h" -#include <memory> +#include "platform/graphics/PaintInvalidationReason.h" namespace blink { +class LayoutBlock; +struct PaintInvalidatorContext; + class DragCaret final : public GarbageCollectedFinalized<DragCaret>, public SynchronousMutationObserver { WTF_MAKE_NONCOPYABLE(DragCaret); @@ -43,9 +47,19 @@ virtual ~DragCaret(); - void paintDragCaret(LocalFrame*, GraphicsContext&, const LayoutPoint&) const; + // Paint invalidation methods delegating to CaretDisplayItemClient. + void clearPreviousVisualRect(const LayoutBlock&); + void layoutBlockWillBeDestroyed(const LayoutBlock&); + void updateStyleAndLayoutIfNeeded(); + void invalidatePaintIfNeeded(const LayoutBlock&, + const PaintInvalidatorContext&, + PaintInvalidationReason); - bool hasCaretIn(const LayoutBlock&) const; + bool shouldPaintCaret(const LayoutBlock&) const; + void paintDragCaret(const LocalFrame*, + GraphicsContext&, + const LayoutPoint&) const; + bool isContentRichlyEditable() const; bool hasCaret() const { return m_position.isNotNull(); } @@ -58,16 +72,11 @@ private: DragCaret(); - void invalidateCaretRect(Node*, const LayoutRect&); - // Implementations of |SynchronousMutationObserver| void nodeChildrenWillBeRemoved(ContainerNode&) final; void nodeWillBeRemoved(Node&) final; PositionWithAffinity m_position; - // caret rect in coords local to the layoutObject responsible for painting the - // caret - LayoutRect m_caretLocalRect; const std::unique_ptr<CaretDisplayItemClient> m_caretBase; };
diff --git a/third_party/WebKit/Source/core/editing/EditingStyleUtilities.cpp b/third_party/WebKit/Source/core/editing/EditingStyleUtilities.cpp new file mode 100644 index 0000000..1df94712 --- /dev/null +++ b/third_party/WebKit/Source/core/editing/EditingStyleUtilities.cpp
@@ -0,0 +1,2063 @@ +/* + * Copyright (C) 2007, 2008, 2009 Apple Computer, Inc. + * Copyright (C) 2010, 2011 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: + * 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. + * + * 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. + */ + +#include "core/editing/EditingStyle.h" + +#include "bindings/core/v8/ExceptionState.h" +#include "core/HTMLNames.h" +#include "core/css/CSSColorValue.h" +#include "core/css/CSSComputedStyleDeclaration.h" +#include "core/css/CSSIdentifierValue.h" +#include "core/css/CSSPrimitiveValue.h" +#include "core/css/CSSPrimitiveValueMappings.h" +#include "core/css/CSSPropertyMetadata.h" +#include "core/css/CSSRuleList.h" +#include "core/css/CSSStyleRule.h" +#include "core/css/CSSValueList.h" +#include "core/css/FontSize.h" +#include "core/css/StylePropertySet.h" +#include "core/css/StyleRule.h" +#include "core/css/parser/CSSParser.h" +#include "core/css/resolver/StyleResolver.h" +#include "core/dom/Document.h" +#include "core/dom/Element.h" +#include "core/dom/Node.h" +#include "core/dom/NodeComputedStyle.h" +#include "core/dom/NodeTraversal.h" +#include "core/dom/QualifiedName.h" +#include "core/editing/EditingUtilities.h" +#include "core/editing/Editor.h" +#include "core/editing/FrameSelection.h" +#include "core/editing/Position.h" +#include "core/editing/commands/ApplyStyleCommand.h" +#include "core/editing/serializers/HTMLInterchange.h" +#include "core/frame/LocalFrame.h" +#include "core/html/HTMLFontElement.h" +#include "core/html/HTMLSpanElement.h" +#include "core/layout/LayoutBox.h" +#include "core/layout/LayoutObject.h" +#include "core/style/ComputedStyle.h" +#include "wtf/StdLibExtras.h" + +namespace blink { + +static const CSSPropertyID& textDecorationPropertyForEditing() { + static const CSSPropertyID property = + RuntimeEnabledFeatures::css3TextDecorationsEnabled() + ? CSSPropertyTextDecorationLine + : CSSPropertyTextDecoration; + return property; +} + +// Editing style properties must be preserved during editing operation. +// e.g. when a user inserts a new paragraph, all properties listed here must be +// copied to the new paragraph. +// NOTE: Use either allEditingProperties() or inheritableEditingProperties() to +// respect runtime enabling of properties. +static const CSSPropertyID staticEditingProperties[] = { + CSSPropertyBackgroundColor, CSSPropertyColor, CSSPropertyFontFamily, + CSSPropertyFontSize, CSSPropertyFontStyle, CSSPropertyFontVariantLigatures, + CSSPropertyFontVariantCaps, CSSPropertyFontWeight, CSSPropertyLetterSpacing, + CSSPropertyOrphans, CSSPropertyTextAlign, + // FIXME: CSSPropertyTextDecoration needs to be removed when CSS3 Text + // Decoration feature is no longer experimental. + CSSPropertyTextDecoration, CSSPropertyTextDecorationLine, + CSSPropertyTextIndent, CSSPropertyTextTransform, CSSPropertyWhiteSpace, + CSSPropertyWidows, CSSPropertyWordSpacing, + CSSPropertyWebkitTextDecorationsInEffect, CSSPropertyWebkitTextFillColor, + CSSPropertyWebkitTextStrokeColor, CSSPropertyWebkitTextStrokeWidth, + CSSPropertyCaretColor}; + +enum EditingPropertiesType { + OnlyInheritableEditingProperties, + AllEditingProperties +}; + +static const Vector<CSSPropertyID>& allEditingProperties() { + DEFINE_STATIC_LOCAL(Vector<CSSPropertyID>, properties, ()); + if (properties.isEmpty()) { + CSSPropertyMetadata::filterEnabledCSSPropertiesIntoVector( + staticEditingProperties, WTF_ARRAY_LENGTH(staticEditingProperties), + properties); + if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()) + properties.remove(properties.find(CSSPropertyTextDecoration)); + } + return properties; +} + +static const Vector<CSSPropertyID>& inheritableEditingProperties() { + DEFINE_STATIC_LOCAL(Vector<CSSPropertyID>, properties, ()); + if (properties.isEmpty()) { + CSSPropertyMetadata::filterEnabledCSSPropertiesIntoVector( + staticEditingProperties, WTF_ARRAY_LENGTH(staticEditingProperties), + properties); + for (size_t index = 0; index < properties.size();) { + if (!CSSPropertyMetadata::isInheritedProperty(properties[index])) { + properties.remove(index); + continue; + } + ++index; + } + } + return properties; +} + +template <class StyleDeclarationType> +static MutableStylePropertySet* copyEditingProperties( + StyleDeclarationType* style, + EditingPropertiesType type = OnlyInheritableEditingProperties) { + if (type == AllEditingProperties) + return style->copyPropertiesInSet(allEditingProperties()); + return style->copyPropertiesInSet(inheritableEditingProperties()); +} + +static inline bool isEditingProperty(int id) { + return allEditingProperties().contains(static_cast<CSSPropertyID>(id)); +} + +static MutableStylePropertySet* editingStyleFromComputedStyle( + CSSComputedStyleDeclaration* style, + EditingPropertiesType type = OnlyInheritableEditingProperties) { + if (!style) + return MutableStylePropertySet::create(HTMLQuirksMode); + return copyEditingProperties(style, type); +} + +static CSSComputedStyleDeclaration* ensureComputedStyle( + const Position& position) { + Element* elem = associatedElementOf(position); + if (!elem) + return nullptr; + return CSSComputedStyleDeclaration::create(elem); +} + +static MutableStylePropertySet* getPropertiesNotIn( + StylePropertySet* styleWithRedundantProperties, + CSSStyleDeclaration* baseStyle); +enum LegacyFontSizeMode { + AlwaysUseLegacyFontSize, + UseLegacyFontSizeOnlyIfPixelValuesMatch +}; +static int legacyFontSizeFromCSSValue(Document*, + const CSSValue*, + bool, + LegacyFontSizeMode); +static bool isTransparentColorValue(const CSSValue*); +static bool hasTransparentBackgroundColor(CSSStyleDeclaration*); +static bool hasTransparentBackgroundColor(StylePropertySet*); +static const CSSValue* backgroundColorValueInEffect(Node*); +static bool hasAncestorVerticalAlignStyle(Node&, CSSValueID); + +class HTMLElementEquivalent : public GarbageCollected<HTMLElementEquivalent> { + public: + static HTMLElementEquivalent* create(CSSPropertyID propertyID, + CSSValueID primitiveValue, + const HTMLQualifiedName& tagName) { + return new HTMLElementEquivalent(propertyID, primitiveValue, tagName); + } + + virtual bool matches(const Element* element) const { + return !m_tagName || element->hasTagName(*m_tagName); + } + virtual bool hasAttribute() const { return false; } + virtual bool propertyExistsInStyle(const StylePropertySet* style) const { + return style->getPropertyCSSValue(m_propertyID); + } + virtual bool valueIsPresentInStyle(HTMLElement*, StylePropertySet*) const; + virtual void addToStyle(Element*, EditingStyle*) const; + + DEFINE_INLINE_VIRTUAL_TRACE() { visitor->trace(m_identifierValue); } + + protected: + HTMLElementEquivalent(CSSPropertyID); + HTMLElementEquivalent(CSSPropertyID, const HTMLQualifiedName& tagName); + HTMLElementEquivalent(CSSPropertyID, + CSSValueID primitiveValue, + const HTMLQualifiedName& tagName); + const CSSPropertyID m_propertyID; + const Member<CSSIdentifierValue> m_identifierValue; + // We can store a pointer because HTML tag names are const global. + const HTMLQualifiedName* m_tagName; +}; + +HTMLElementEquivalent::HTMLElementEquivalent(CSSPropertyID id) + : m_propertyID(id), m_tagName(0) {} + +HTMLElementEquivalent::HTMLElementEquivalent(CSSPropertyID id, + const HTMLQualifiedName& tagName) + : m_propertyID(id), m_tagName(&tagName) {} + +HTMLElementEquivalent::HTMLElementEquivalent(CSSPropertyID id, + CSSValueID valueID, + const HTMLQualifiedName& tagName) + : m_propertyID(id), + m_identifierValue(CSSIdentifierValue::create(valueID)), + m_tagName(&tagName) { + DCHECK_NE(valueID, CSSValueInvalid); +} + +bool HTMLElementEquivalent::valueIsPresentInStyle( + HTMLElement* element, + StylePropertySet* style) const { + const CSSValue* value = style->getPropertyCSSValue(m_propertyID); + return matches(element) && value && value->isIdentifierValue() && + toCSSIdentifierValue(value)->getValueID() == + m_identifierValue->getValueID(); +} + +void HTMLElementEquivalent::addToStyle(Element*, EditingStyle* style) const { + style->setProperty(m_propertyID, m_identifierValue->cssText()); +} + +class HTMLTextDecorationEquivalent final : public HTMLElementEquivalent { + public: + static HTMLElementEquivalent* create(CSSValueID primitiveValue, + const HTMLQualifiedName& tagName) { + return new HTMLTextDecorationEquivalent(primitiveValue, tagName); + } + bool propertyExistsInStyle(const StylePropertySet*) const override; + bool valueIsPresentInStyle(HTMLElement*, StylePropertySet*) const override; + + DEFINE_INLINE_VIRTUAL_TRACE() { HTMLElementEquivalent::trace(visitor); } + + private: + HTMLTextDecorationEquivalent(CSSValueID primitiveValue, + const HTMLQualifiedName& tagName); +}; + +HTMLTextDecorationEquivalent::HTMLTextDecorationEquivalent( + CSSValueID primitiveValue, + const HTMLQualifiedName& tagName) + : HTMLElementEquivalent(textDecorationPropertyForEditing(), + primitiveValue, + tagName) +// m_propertyID is used in HTMLElementEquivalent::addToStyle +{} + +bool HTMLTextDecorationEquivalent::propertyExistsInStyle( + const StylePropertySet* style) const { + return style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect) || + style->getPropertyCSSValue(textDecorationPropertyForEditing()); +} + +bool HTMLTextDecorationEquivalent::valueIsPresentInStyle( + HTMLElement* element, + StylePropertySet* style) const { + const CSSValue* styleValue = + style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect); + if (!styleValue) + styleValue = style->getPropertyCSSValue(textDecorationPropertyForEditing()); + return matches(element) && styleValue && styleValue->isValueList() && + toCSSValueList(styleValue)->hasValue(*m_identifierValue); +} + +class HTMLAttributeEquivalent : public HTMLElementEquivalent { + public: + static HTMLAttributeEquivalent* create(CSSPropertyID propertyID, + const HTMLQualifiedName& tagName, + const QualifiedName& attrName) { + return new HTMLAttributeEquivalent(propertyID, tagName, attrName); + } + static HTMLAttributeEquivalent* create(CSSPropertyID propertyID, + const QualifiedName& attrName) { + return new HTMLAttributeEquivalent(propertyID, attrName); + } + + bool matches(const Element* element) const override { + return HTMLElementEquivalent::matches(element) && + element->hasAttribute(m_attrName); + } + bool hasAttribute() const override { return true; } + bool valueIsPresentInStyle(HTMLElement*, StylePropertySet*) const override; + void addToStyle(Element*, EditingStyle*) const override; + virtual const CSSValue* attributeValueAsCSSValue(Element*) const; + inline const QualifiedName& attributeName() const { return m_attrName; } + + DEFINE_INLINE_VIRTUAL_TRACE() { HTMLElementEquivalent::trace(visitor); } + + protected: + HTMLAttributeEquivalent(CSSPropertyID, + const HTMLQualifiedName& tagName, + const QualifiedName& attrName); + HTMLAttributeEquivalent(CSSPropertyID, const QualifiedName& attrName); + // We can store a reference because HTML attribute names are const global. + const QualifiedName& m_attrName; +}; + +HTMLAttributeEquivalent::HTMLAttributeEquivalent( + CSSPropertyID id, + const HTMLQualifiedName& tagName, + const QualifiedName& attrName) + : HTMLElementEquivalent(id, tagName), m_attrName(attrName) {} + +HTMLAttributeEquivalent::HTMLAttributeEquivalent(CSSPropertyID id, + const QualifiedName& attrName) + : HTMLElementEquivalent(id), m_attrName(attrName) {} + +bool HTMLAttributeEquivalent::valueIsPresentInStyle( + HTMLElement* element, + StylePropertySet* style) const { + const CSSValue* value = attributeValueAsCSSValue(element); + const CSSValue* styleValue = style->getPropertyCSSValue(m_propertyID); + + return compareCSSValuePtr(value, styleValue); +} + +void HTMLAttributeEquivalent::addToStyle(Element* element, + EditingStyle* style) const { + if (const CSSValue* value = attributeValueAsCSSValue(element)) + style->setProperty(m_propertyID, value->cssText()); +} + +const CSSValue* HTMLAttributeEquivalent::attributeValueAsCSSValue( + Element* element) const { + DCHECK(element); + const AtomicString& value = element->getAttribute(m_attrName); + if (value.isNull()) + return nullptr; + + MutableStylePropertySet* dummyStyle = nullptr; + dummyStyle = MutableStylePropertySet::create(HTMLQuirksMode); + dummyStyle->setProperty(m_propertyID, value); + return dummyStyle->getPropertyCSSValue(m_propertyID); +} + +class HTMLFontSizeEquivalent final : public HTMLAttributeEquivalent { + public: + static HTMLFontSizeEquivalent* create() { + return new HTMLFontSizeEquivalent(); + } + const CSSValue* attributeValueAsCSSValue(Element*) const override; + + DEFINE_INLINE_VIRTUAL_TRACE() { HTMLAttributeEquivalent::trace(visitor); } + + private: + HTMLFontSizeEquivalent(); +}; + +HTMLFontSizeEquivalent::HTMLFontSizeEquivalent() + : HTMLAttributeEquivalent(CSSPropertyFontSize, + HTMLNames::fontTag, + HTMLNames::sizeAttr) {} + +const CSSValue* HTMLFontSizeEquivalent::attributeValueAsCSSValue( + Element* element) const { + DCHECK(element); + const AtomicString& value = element->getAttribute(m_attrName); + if (value.isNull()) + return nullptr; + CSSValueID size; + if (!HTMLFontElement::cssValueFromFontSizeNumber(value, size)) + return nullptr; + return CSSIdentifierValue::create(size); +} + +float EditingStyle::NoFontDelta = 0.0f; + +EditingStyle::EditingStyle(ContainerNode* node, + PropertiesToInclude propertiesToInclude) { + init(node, propertiesToInclude); +} + +EditingStyle::EditingStyle(const Position& position, + PropertiesToInclude propertiesToInclude) { + init(position.anchorNode(), propertiesToInclude); +} + +EditingStyle::EditingStyle(const StylePropertySet* style) + : m_mutableStyle(style ? style->mutableCopy() : nullptr) { + extractFontSizeDelta(); +} + +EditingStyle::EditingStyle(CSSPropertyID propertyID, const String& value) + : m_mutableStyle(nullptr) { + setProperty(propertyID, value); + m_isVerticalAlign = propertyID == CSSPropertyVerticalAlign && + (value == "sub" || value == "super"); +} + +static Color cssValueToColor(const CSSValue* colorValue) { + if (!colorValue || + (!colorValue->isColorValue() && !colorValue->isPrimitiveValue() && + !colorValue->isIdentifierValue())) + return Color::transparent; + + if (colorValue->isColorValue()) + return toCSSColorValue(colorValue)->value(); + + Color color = 0; + // FIXME: Why ignore the return value? + CSSParser::parseColor(color, colorValue->cssText()); + return color; +} + +static inline Color getFontColor(CSSStyleDeclaration* style) { + return cssValueToColor(style->getPropertyCSSValueInternal(CSSPropertyColor)); +} + +static inline Color getFontColor(StylePropertySet* style) { + return cssValueToColor(style->getPropertyCSSValue(CSSPropertyColor)); +} + +static inline Color getBackgroundColor(CSSStyleDeclaration* style) { + return cssValueToColor( + style->getPropertyCSSValueInternal(CSSPropertyBackgroundColor)); +} + +static inline Color getBackgroundColor(StylePropertySet* style) { + return cssValueToColor( + style->getPropertyCSSValue(CSSPropertyBackgroundColor)); +} + +static inline Color backgroundColorInEffect(Node* node) { + return cssValueToColor(backgroundColorValueInEffect(node)); +} + +static int textAlignResolvingStartAndEnd(int textAlign, int direction) { + switch (textAlign) { + case CSSValueCenter: + case CSSValueWebkitCenter: + return CSSValueCenter; + case CSSValueJustify: + return CSSValueJustify; + case CSSValueLeft: + case CSSValueWebkitLeft: + return CSSValueLeft; + case CSSValueRight: + case CSSValueWebkitRight: + return CSSValueRight; + case CSSValueStart: + return direction != CSSValueRtl ? CSSValueLeft : CSSValueRight; + case CSSValueEnd: + return direction == CSSValueRtl ? CSSValueRight : CSSValueLeft; + } + return CSSValueInvalid; +} + +template <typename T> +static int textAlignResolvingStartAndEnd(T* style) { + return textAlignResolvingStartAndEnd( + getIdentifierValue(style, CSSPropertyTextAlign), + getIdentifierValue(style, CSSPropertyDirection)); +} + +void EditingStyle::init(Node* node, PropertiesToInclude propertiesToInclude) { + if (isTabHTMLSpanElementTextNode(node)) + node = tabSpanElement(node)->parentNode(); + else if (isTabHTMLSpanElement(node)) + node = node->parentNode(); + + CSSComputedStyleDeclaration* computedStyleAtPosition = + CSSComputedStyleDeclaration::create(node); + m_mutableStyle = + propertiesToInclude == AllProperties && computedStyleAtPosition + ? computedStyleAtPosition->copyProperties() + : editingStyleFromComputedStyle(computedStyleAtPosition); + + if (propertiesToInclude == EditingPropertiesInEffect) { + if (const CSSValue* value = backgroundColorValueInEffect(node)) + m_mutableStyle->setProperty(CSSPropertyBackgroundColor, value->cssText()); + if (const CSSValue* value = computedStyleAtPosition->getPropertyCSSValue( + CSSPropertyWebkitTextDecorationsInEffect)) + m_mutableStyle->setProperty(CSSPropertyTextDecoration, value->cssText()); + } + + if (node && node->ensureComputedStyle()) { + const ComputedStyle* computedStyle = node->ensureComputedStyle(); + removeInheritedColorsIfNeeded(computedStyle); + replaceFontSizeByKeywordIfPossible(computedStyle, computedStyleAtPosition); + } + + m_isMonospaceFont = computedStyleAtPosition->isMonospaceFont(); + extractFontSizeDelta(); +} + +void EditingStyle::removeInheritedColorsIfNeeded( + const ComputedStyle* computedStyle) { + // If a node's text fill color is currentColor, then its children use + // their font-color as their text fill color (they don't + // inherit it). Likewise for stroke color. + // Similar thing happens for caret-color if it's auto or currentColor. + if (computedStyle->textFillColor().isCurrentColor()) + m_mutableStyle->removeProperty(CSSPropertyWebkitTextFillColor); + if (computedStyle->textStrokeColor().isCurrentColor()) + m_mutableStyle->removeProperty(CSSPropertyWebkitTextStrokeColor); + if (computedStyle->caretColor().isAutoColor() || + computedStyle->caretColor().isCurrentColor()) + m_mutableStyle->removeProperty(CSSPropertyCaretColor); +} + +void EditingStyle::setProperty(CSSPropertyID propertyID, + const String& value, + bool important) { + if (!m_mutableStyle) + m_mutableStyle = MutableStylePropertySet::create(HTMLQuirksMode); + + m_mutableStyle->setProperty(propertyID, value, important); +} + +void EditingStyle::replaceFontSizeByKeywordIfPossible( + const ComputedStyle* computedStyle, + CSSComputedStyleDeclaration* cssComputedStyle) { + DCHECK(computedStyle); + if (computedStyle->getFontDescription().keywordSize()) { + m_mutableStyle->setProperty( + CSSPropertyFontSize, + cssComputedStyle->getFontSizeCSSValuePreferringKeyword()->cssText()); + } +} + +void EditingStyle::extractFontSizeDelta() { + if (!m_mutableStyle) + return; + + if (m_mutableStyle->getPropertyCSSValue(CSSPropertyFontSize)) { + // Explicit font size overrides any delta. + m_mutableStyle->removeProperty(CSSPropertyWebkitFontSizeDelta); + return; + } + + // Get the adjustment amount out of the style. + const CSSValue* value = + m_mutableStyle->getPropertyCSSValue(CSSPropertyWebkitFontSizeDelta); + if (!value || !value->isPrimitiveValue()) + return; + + const CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); + + // Only PX handled now. If we handle more types in the future, perhaps + // a switch statement here would be more appropriate. + if (!primitiveValue->isPx()) + return; + + m_fontSizeDelta = primitiveValue->getFloatValue(); + m_mutableStyle->removeProperty(CSSPropertyWebkitFontSizeDelta); +} + +bool EditingStyle::isEmpty() const { + return (!m_mutableStyle || m_mutableStyle->isEmpty()) && + m_fontSizeDelta == NoFontDelta; +} + +bool EditingStyle::textDirection(WritingDirection& writingDirection) const { + if (!m_mutableStyle) + return false; + + const CSSValue* unicodeBidi = + m_mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi); + if (!unicodeBidi || !unicodeBidi->isIdentifierValue()) + return false; + + CSSValueID unicodeBidiValue = toCSSIdentifierValue(unicodeBidi)->getValueID(); + if (isEmbedOrIsolate(unicodeBidiValue)) { + const CSSValue* direction = + m_mutableStyle->getPropertyCSSValue(CSSPropertyDirection); + if (!direction || !direction->isIdentifierValue()) + return false; + + writingDirection = + toCSSIdentifierValue(direction)->getValueID() == CSSValueLtr + ? LeftToRightWritingDirection + : RightToLeftWritingDirection; + + return true; + } + + if (unicodeBidiValue == CSSValueNormal) { + writingDirection = NaturalWritingDirection; + return true; + } + + return false; +} + +void EditingStyle::overrideWithStyle(const StylePropertySet* style) { + if (!style || style->isEmpty()) + return; + if (!m_mutableStyle) + m_mutableStyle = MutableStylePropertySet::create(HTMLQuirksMode); + m_mutableStyle->mergeAndOverrideOnConflict(style); + extractFontSizeDelta(); +} + +void EditingStyle::clear() { + m_mutableStyle.clear(); + m_isMonospaceFont = false; + m_fontSizeDelta = NoFontDelta; +} + +EditingStyle* EditingStyle::copy() const { + EditingStyle* copy = EditingStyle::create(); + if (m_mutableStyle) + copy->m_mutableStyle = m_mutableStyle->mutableCopy(); + copy->m_isMonospaceFont = m_isMonospaceFont; + copy->m_fontSizeDelta = m_fontSizeDelta; + return copy; +} + +// This is the list of CSS properties that apply specially to block-level +// elements. +static const CSSPropertyID staticBlockProperties[] = { + CSSPropertyBreakAfter, + CSSPropertyBreakBefore, + CSSPropertyBreakInside, + CSSPropertyOrphans, + CSSPropertyOverflow, // This can be also be applied to replaced elements + CSSPropertyColumnCount, + CSSPropertyColumnGap, + CSSPropertyColumnRuleColor, + CSSPropertyColumnRuleStyle, + CSSPropertyColumnRuleWidth, + CSSPropertyWebkitColumnBreakBefore, + CSSPropertyWebkitColumnBreakAfter, + CSSPropertyWebkitColumnBreakInside, + CSSPropertyColumnWidth, + CSSPropertyPageBreakAfter, + CSSPropertyPageBreakBefore, + CSSPropertyPageBreakInside, + CSSPropertyTextAlign, + CSSPropertyTextAlignLast, + CSSPropertyTextIndent, + CSSPropertyTextJustify, + CSSPropertyWidows}; + +static const Vector<CSSPropertyID>& blockPropertiesVector() { + DEFINE_STATIC_LOCAL(Vector<CSSPropertyID>, properties, ()); + if (properties.isEmpty()) { + CSSPropertyMetadata::filterEnabledCSSPropertiesIntoVector( + staticBlockProperties, WTF_ARRAY_LENGTH(staticBlockProperties), + properties); + } + return properties; +} + +EditingStyle* EditingStyle::extractAndRemoveBlockProperties() { + EditingStyle* blockProperties = EditingStyle::create(); + if (!m_mutableStyle) + return blockProperties; + + blockProperties->m_mutableStyle = + m_mutableStyle->copyPropertiesInSet(blockPropertiesVector()); + removeBlockProperties(); + + return blockProperties; +} + +EditingStyle* EditingStyle::extractAndRemoveTextDirection() { + EditingStyle* textDirection = EditingStyle::create(); + textDirection->m_mutableStyle = + MutableStylePropertySet::create(HTMLQuirksMode); + textDirection->m_mutableStyle->setProperty( + CSSPropertyUnicodeBidi, CSSValueIsolate, + m_mutableStyle->propertyIsImportant(CSSPropertyUnicodeBidi)); + textDirection->m_mutableStyle->setProperty( + CSSPropertyDirection, + m_mutableStyle->getPropertyValue(CSSPropertyDirection), + m_mutableStyle->propertyIsImportant(CSSPropertyDirection)); + + m_mutableStyle->removeProperty(CSSPropertyUnicodeBidi); + m_mutableStyle->removeProperty(CSSPropertyDirection); + + return textDirection; +} + +void EditingStyle::removeBlockProperties() { + if (!m_mutableStyle) + return; + + m_mutableStyle->removePropertiesInSet(blockPropertiesVector().data(), + blockPropertiesVector().size()); +} + +void EditingStyle::removeStyleAddedByElement(Element* element) { + if (!element || !element->parentNode()) + return; + MutableStylePropertySet* parentStyle = editingStyleFromComputedStyle( + CSSComputedStyleDeclaration::create(element->parentNode()), + AllEditingProperties); + MutableStylePropertySet* nodeStyle = editingStyleFromComputedStyle( + CSSComputedStyleDeclaration::create(element), AllEditingProperties); + nodeStyle->removeEquivalentProperties(parentStyle); + m_mutableStyle->removeEquivalentProperties(nodeStyle); +} + +void EditingStyle::removeStyleConflictingWithStyleOfElement(Element* element) { + if (!element || !element->parentNode() || !m_mutableStyle) + return; + + MutableStylePropertySet* parentStyle = editingStyleFromComputedStyle( + CSSComputedStyleDeclaration::create(element->parentNode()), + AllEditingProperties); + MutableStylePropertySet* nodeStyle = editingStyleFromComputedStyle( + CSSComputedStyleDeclaration::create(element), AllEditingProperties); + nodeStyle->removeEquivalentProperties(parentStyle); + + unsigned propertyCount = nodeStyle->propertyCount(); + for (unsigned i = 0; i < propertyCount; ++i) + m_mutableStyle->removeProperty(nodeStyle->propertyAt(i).id()); +} + +void EditingStyle::collapseTextDecorationProperties() { + if (!m_mutableStyle) + return; + + const CSSValue* textDecorationsInEffect = m_mutableStyle->getPropertyCSSValue( + CSSPropertyWebkitTextDecorationsInEffect); + if (!textDecorationsInEffect) + return; + + if (textDecorationsInEffect->isValueList()) { + m_mutableStyle->setProperty(textDecorationPropertyForEditing(), + textDecorationsInEffect->cssText(), + m_mutableStyle->propertyIsImportant( + textDecorationPropertyForEditing())); + } else { + m_mutableStyle->removeProperty(textDecorationPropertyForEditing()); + } + m_mutableStyle->removeProperty(CSSPropertyWebkitTextDecorationsInEffect); +} + +// CSS properties that create a visual difference only when applied to text. +static const CSSPropertyID textOnlyProperties[] = { + // FIXME: CSSPropertyTextDecoration needs to be removed when CSS3 Text + // Decoration feature is no longer experimental. + CSSPropertyTextDecoration, + CSSPropertyTextDecorationLine, + CSSPropertyWebkitTextDecorationsInEffect, + CSSPropertyFontStyle, + CSSPropertyFontWeight, + CSSPropertyColor, +}; + +TriState EditingStyle::triStateOfStyle(EditingStyle* style) const { + if (!style || !style->m_mutableStyle) + return FalseTriState; + return triStateOfStyle(style->m_mutableStyle->ensureCSSStyleDeclaration(), + DoNotIgnoreTextOnlyProperties); +} + +TriState EditingStyle::triStateOfStyle( + CSSStyleDeclaration* styleToCompare, + ShouldIgnoreTextOnlyProperties shouldIgnoreTextOnlyProperties) const { + MutableStylePropertySet* difference = + getPropertiesNotIn(m_mutableStyle.get(), styleToCompare); + + if (shouldIgnoreTextOnlyProperties == IgnoreTextOnlyProperties) { + difference->removePropertiesInSet(textOnlyProperties, + WTF_ARRAY_LENGTH(textOnlyProperties)); + } + + if (difference->isEmpty()) + return TrueTriState; + if (difference->propertyCount() == m_mutableStyle->propertyCount()) + return FalseTriState; + + return MixedTriState; +} + +static bool hasAncestorVerticalAlignStyle(Node& node, CSSValueID value) { + for (Node& runner : NodeTraversal::inclusiveAncestorsOf(node)) { + CSSComputedStyleDeclaration* ancestorStyle = + CSSComputedStyleDeclaration::create(&runner); + if (getIdentifierValue(ancestorStyle, CSSPropertyVerticalAlign) == value) + return true; + } + return false; +} + +TriState EditingStyle::triStateOfStyle( + const VisibleSelection& selection) const { + if (selection.isNone()) + return FalseTriState; + + if (selection.isCaret()) + return triStateOfStyle(EditingStyle::styleAtSelectionStart(selection)); + + TriState state = FalseTriState; + bool nodeIsStart = true; + for (Node& node : NodeTraversal::startsAt(*selection.start().anchorNode())) { + if (node.layoutObject() && hasEditableStyle(node)) { + CSSComputedStyleDeclaration* nodeStyle = + CSSComputedStyleDeclaration::create(&node); + if (nodeStyle) { + // If the selected element has <sub> or <sup> ancestor element, apply + // the corresponding style(vertical-align) to it so that + // document.queryCommandState() works with the style. See bug + // http://crbug.com/582225. + if (m_isVerticalAlign && + getIdentifierValue(nodeStyle, CSSPropertyVerticalAlign) == + CSSValueBaseline) { + const CSSIdentifierValue* verticalAlign = toCSSIdentifierValue( + m_mutableStyle->getPropertyCSSValue(CSSPropertyVerticalAlign)); + if (hasAncestorVerticalAlignStyle(node, + verticalAlign->getValueID())) { + node.mutableComputedStyle()->setVerticalAlign( + verticalAlign->convertTo<EVerticalAlign>()); + } + } + + // Pass EditingStyle::DoNotIgnoreTextOnlyProperties without checking if + // node.isTextNode() because the node can be an element node. See bug + // http://crbug.com/584939. + TriState nodeState = triStateOfStyle( + nodeStyle, EditingStyle::DoNotIgnoreTextOnlyProperties); + if (nodeIsStart) { + state = nodeState; + nodeIsStart = false; + } else if (state != nodeState && node.isTextNode()) { + state = MixedTriState; + break; + } + } + } + if (&node == selection.end().anchorNode()) + break; + } + + return state; +} + +bool EditingStyle::conflictsWithInlineStyleOfElement( + HTMLElement* element, + EditingStyle* extractedStyle, + Vector<CSSPropertyID>* conflictingProperties) const { + DCHECK(element); + DCHECK(!conflictingProperties || conflictingProperties->isEmpty()); + + const StylePropertySet* inlineStyle = element->inlineStyle(); + if (!m_mutableStyle || !inlineStyle) + return false; + + unsigned propertyCount = m_mutableStyle->propertyCount(); + for (unsigned i = 0; i < propertyCount; ++i) { + CSSPropertyID propertyID = m_mutableStyle->propertyAt(i).id(); + + // We don't override whitespace property of a tab span because that would + // collapse the tab into a space. + if (propertyID == CSSPropertyWhiteSpace && isTabHTMLSpanElement(element)) + continue; + + if (propertyID == CSSPropertyWebkitTextDecorationsInEffect && + inlineStyle->getPropertyCSSValue(textDecorationPropertyForEditing())) { + if (!conflictingProperties) + return true; + conflictingProperties->push_back(CSSPropertyTextDecoration); + // Because text-decoration expands to text-decoration-line when CSS3 + // Text Decoration is enabled, we also state it as conflicting. + if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()) + conflictingProperties->push_back(CSSPropertyTextDecorationLine); + if (extractedStyle) { + extractedStyle->setProperty( + textDecorationPropertyForEditing(), + inlineStyle->getPropertyValue(textDecorationPropertyForEditing()), + inlineStyle->propertyIsImportant( + textDecorationPropertyForEditing())); + } + continue; + } + + if (!inlineStyle->getPropertyCSSValue(propertyID)) + continue; + + if (propertyID == CSSPropertyUnicodeBidi && + inlineStyle->getPropertyCSSValue(CSSPropertyDirection)) { + if (!conflictingProperties) + return true; + conflictingProperties->push_back(CSSPropertyDirection); + if (extractedStyle) { + extractedStyle->setProperty( + propertyID, inlineStyle->getPropertyValue(propertyID), + inlineStyle->propertyIsImportant(propertyID)); + } + } + + if (!conflictingProperties) + return true; + + conflictingProperties->push_back(propertyID); + + if (extractedStyle) { + extractedStyle->setProperty(propertyID, + inlineStyle->getPropertyValue(propertyID), + inlineStyle->propertyIsImportant(propertyID)); + } + } + + return conflictingProperties && !conflictingProperties->isEmpty(); +} + +static const HeapVector<Member<HTMLElementEquivalent>>& +htmlElementEquivalents() { + DEFINE_STATIC_LOCAL(HeapVector<Member<HTMLElementEquivalent>>, + HTMLElementEquivalents, + (new HeapVector<Member<HTMLElementEquivalent>>)); + if (!HTMLElementEquivalents.size()) { + HTMLElementEquivalents.push_back(HTMLElementEquivalent::create( + CSSPropertyFontWeight, CSSValueBold, HTMLNames::bTag)); + HTMLElementEquivalents.push_back(HTMLElementEquivalent::create( + CSSPropertyFontWeight, CSSValueBold, HTMLNames::strongTag)); + HTMLElementEquivalents.push_back(HTMLElementEquivalent::create( + CSSPropertyVerticalAlign, CSSValueSub, HTMLNames::subTag)); + HTMLElementEquivalents.push_back(HTMLElementEquivalent::create( + CSSPropertyVerticalAlign, CSSValueSuper, HTMLNames::supTag)); + HTMLElementEquivalents.push_back(HTMLElementEquivalent::create( + CSSPropertyFontStyle, CSSValueItalic, HTMLNames::iTag)); + HTMLElementEquivalents.push_back(HTMLElementEquivalent::create( + CSSPropertyFontStyle, CSSValueItalic, HTMLNames::emTag)); + + HTMLElementEquivalents.push_back(HTMLTextDecorationEquivalent::create( + CSSValueUnderline, HTMLNames::uTag)); + HTMLElementEquivalents.push_back(HTMLTextDecorationEquivalent::create( + CSSValueLineThrough, HTMLNames::sTag)); + HTMLElementEquivalents.push_back(HTMLTextDecorationEquivalent::create( + CSSValueLineThrough, HTMLNames::strikeTag)); + } + + return HTMLElementEquivalents; +} + +bool EditingStyle::conflictsWithImplicitStyleOfElement( + HTMLElement* element, + EditingStyle* extractedStyle, + ShouldExtractMatchingStyle shouldExtractMatchingStyle) const { + if (!m_mutableStyle) + return false; + + const HeapVector<Member<HTMLElementEquivalent>>& HTMLElementEquivalents = + htmlElementEquivalents(); + for (size_t i = 0; i < HTMLElementEquivalents.size(); ++i) { + const HTMLElementEquivalent* equivalent = HTMLElementEquivalents[i].get(); + if (equivalent->matches(element) && + equivalent->propertyExistsInStyle(m_mutableStyle.get()) && + (shouldExtractMatchingStyle == ExtractMatchingStyle || + !equivalent->valueIsPresentInStyle(element, m_mutableStyle.get()))) { + if (extractedStyle) + equivalent->addToStyle(element, extractedStyle); + return true; + } + } + return false; +} + +static const HeapVector<Member<HTMLAttributeEquivalent>>& +htmlAttributeEquivalents() { + DEFINE_STATIC_LOCAL(HeapVector<Member<HTMLAttributeEquivalent>>, + HTMLAttributeEquivalents, + (new HeapVector<Member<HTMLAttributeEquivalent>>)); + if (!HTMLAttributeEquivalents.size()) { + // elementIsStyledSpanOrHTMLEquivalent depends on the fact each + // HTMLAttriuteEquivalent matches exactly one attribute of exactly one + // element except dirAttr. + HTMLAttributeEquivalents.push_back(HTMLAttributeEquivalent::create( + CSSPropertyColor, HTMLNames::fontTag, HTMLNames::colorAttr)); + HTMLAttributeEquivalents.push_back(HTMLAttributeEquivalent::create( + CSSPropertyFontFamily, HTMLNames::fontTag, HTMLNames::faceAttr)); + HTMLAttributeEquivalents.push_back(HTMLFontSizeEquivalent::create()); + + HTMLAttributeEquivalents.push_back(HTMLAttributeEquivalent::create( + CSSPropertyDirection, HTMLNames::dirAttr)); + HTMLAttributeEquivalents.push_back(HTMLAttributeEquivalent::create( + CSSPropertyUnicodeBidi, HTMLNames::dirAttr)); + } + + return HTMLAttributeEquivalents; +} + +bool EditingStyle::conflictsWithImplicitStyleOfAttributes( + HTMLElement* element) const { + DCHECK(element); + if (!m_mutableStyle) + return false; + + const HeapVector<Member<HTMLAttributeEquivalent>>& HTMLAttributeEquivalents = + htmlAttributeEquivalents(); + for (const auto& equivalent : HTMLAttributeEquivalents) { + if (equivalent->matches(element) && + equivalent->propertyExistsInStyle(m_mutableStyle.get()) && + !equivalent->valueIsPresentInStyle(element, m_mutableStyle.get())) + return true; + } + + return false; +} + +bool EditingStyle::extractConflictingImplicitStyleOfAttributes( + HTMLElement* element, + ShouldPreserveWritingDirection shouldPreserveWritingDirection, + EditingStyle* extractedStyle, + Vector<QualifiedName>& conflictingAttributes, + ShouldExtractMatchingStyle shouldExtractMatchingStyle) const { + DCHECK(element); + // HTMLAttributeEquivalent::addToStyle doesn't support unicode-bidi and + // direction properties + if (extractedStyle) + DCHECK_EQ(shouldPreserveWritingDirection, PreserveWritingDirection); + if (!m_mutableStyle) + return false; + + const HeapVector<Member<HTMLAttributeEquivalent>>& HTMLAttributeEquivalents = + htmlAttributeEquivalents(); + bool removed = false; + for (const auto& attribute : HTMLAttributeEquivalents) { + const HTMLAttributeEquivalent* equivalent = attribute.get(); + + // unicode-bidi and direction are pushed down separately so don't push down + // with other styles. + if (shouldPreserveWritingDirection == PreserveWritingDirection && + equivalent->attributeName() == HTMLNames::dirAttr) + continue; + + if (!equivalent->matches(element) || + !equivalent->propertyExistsInStyle(m_mutableStyle.get()) || + (shouldExtractMatchingStyle == DoNotExtractMatchingStyle && + equivalent->valueIsPresentInStyle(element, m_mutableStyle.get()))) + continue; + + if (extractedStyle) + equivalent->addToStyle(element, extractedStyle); + conflictingAttributes.push_back(equivalent->attributeName()); + removed = true; + } + + return removed; +} + +bool EditingStyle::styleIsPresentInComputedStyleOfNode(Node* node) const { + return !m_mutableStyle || + getPropertiesNotIn(m_mutableStyle.get(), + CSSComputedStyleDeclaration::create(node)) + ->isEmpty(); +} + +bool EditingStyle::elementIsStyledSpanOrHTMLEquivalent( + const HTMLElement* element) { + DCHECK(element); + bool elementIsSpanOrElementEquivalent = false; + if (isHTMLSpanElement(*element)) { + elementIsSpanOrElementEquivalent = true; + } else { + const HeapVector<Member<HTMLElementEquivalent>>& HTMLElementEquivalents = + htmlElementEquivalents(); + size_t i; + for (i = 0; i < HTMLElementEquivalents.size(); ++i) { + if (HTMLElementEquivalents[i]->matches(element)) { + elementIsSpanOrElementEquivalent = true; + break; + } + } + } + + AttributeCollection attributes = element->attributes(); + if (attributes.isEmpty()) { + // span, b, etc... without any attributes + return elementIsSpanOrElementEquivalent; + } + + unsigned matchedAttributes = 0; + const HeapVector<Member<HTMLAttributeEquivalent>>& HTMLAttributeEquivalents = + htmlAttributeEquivalents(); + for (const auto& equivalent : HTMLAttributeEquivalents) { + if (equivalent->matches(element) && + equivalent->attributeName() != HTMLNames::dirAttr) + matchedAttributes++; + } + + if (!elementIsSpanOrElementEquivalent && !matchedAttributes) { + // element is not a span, a html element equivalent, or font element. + return false; + } + + if (element->getAttribute(HTMLNames::classAttr) == AppleStyleSpanClass) + matchedAttributes++; + + if (element->hasAttribute(HTMLNames::styleAttr)) { + if (const StylePropertySet* style = element->inlineStyle()) { + unsigned propertyCount = style->propertyCount(); + for (unsigned i = 0; i < propertyCount; ++i) { + if (!isEditingProperty(style->propertyAt(i).id())) + return false; + } + } + matchedAttributes++; + } + + // font with color attribute, span with style attribute, etc... + DCHECK_LE(matchedAttributes, attributes.size()); + return matchedAttributes >= attributes.size(); +} + +void EditingStyle::prepareToApplyAt( + const Position& position, + ShouldPreserveWritingDirection shouldPreserveWritingDirection) { + if (!m_mutableStyle) + return; + + // ReplaceSelectionCommand::handleStyleSpans() requires that this function + // only removes the editing style. If this function was modified in the future + // to delete all redundant properties, then add a boolean value to indicate + // which one of editingStyleAtPosition or computedStyle is called. + EditingStyle* editingStyleAtPosition = + EditingStyle::create(position, EditingPropertiesInEffect); + StylePropertySet* styleAtPosition = + editingStyleAtPosition->m_mutableStyle.get(); + + const CSSValue* unicodeBidi = nullptr; + const CSSValue* direction = nullptr; + if (shouldPreserveWritingDirection == PreserveWritingDirection) { + unicodeBidi = m_mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi); + direction = m_mutableStyle->getPropertyCSSValue(CSSPropertyDirection); + } + + m_mutableStyle->removeEquivalentProperties(styleAtPosition); + + if (textAlignResolvingStartAndEnd(m_mutableStyle.get()) == + textAlignResolvingStartAndEnd(styleAtPosition)) + m_mutableStyle->removeProperty(CSSPropertyTextAlign); + + if (getFontColor(m_mutableStyle.get()) == getFontColor(styleAtPosition)) + m_mutableStyle->removeProperty(CSSPropertyColor); + + if (hasTransparentBackgroundColor(m_mutableStyle.get()) || + cssValueToColor( + m_mutableStyle->getPropertyCSSValue(CSSPropertyBackgroundColor)) == + backgroundColorInEffect(position.computeContainerNode())) + m_mutableStyle->removeProperty(CSSPropertyBackgroundColor); + + if (unicodeBidi && unicodeBidi->isIdentifierValue()) { + m_mutableStyle->setProperty( + CSSPropertyUnicodeBidi, + toCSSIdentifierValue(unicodeBidi)->getValueID()); + if (direction && direction->isIdentifierValue()) { + m_mutableStyle->setProperty( + CSSPropertyDirection, toCSSIdentifierValue(direction)->getValueID()); + } + } +} + +void EditingStyle::mergeTypingStyle(Document* document) { + DCHECK(document); + + EditingStyle* typingStyle = document->frame()->selection().typingStyle(); + if (!typingStyle || typingStyle == this) + return; + + mergeStyle(typingStyle->style(), OverrideValues); +} + +void EditingStyle::mergeInlineStyleOfElement( + HTMLElement* element, + CSSPropertyOverrideMode mode, + PropertiesToInclude propertiesToInclude) { + DCHECK(element); + if (!element->inlineStyle()) + return; + + switch (propertiesToInclude) { + case AllProperties: + mergeStyle(element->inlineStyle(), mode); + return; + case OnlyEditingInheritableProperties: + mergeStyle(copyEditingProperties(element->inlineStyle(), + OnlyInheritableEditingProperties), + mode); + return; + case EditingPropertiesInEffect: + mergeStyle( + copyEditingProperties(element->inlineStyle(), AllEditingProperties), + mode); + return; + } +} + +static inline bool elementMatchesAndPropertyIsNotInInlineStyleDecl( + const HTMLElementEquivalent* equivalent, + const Element* element, + EditingStyle::CSSPropertyOverrideMode mode, + StylePropertySet* style) { + return equivalent->matches(element) && + (!element->inlineStyle() || + !equivalent->propertyExistsInStyle(element->inlineStyle())) && + (mode == EditingStyle::OverrideValues || + !equivalent->propertyExistsInStyle(style)); +} + +static MutableStylePropertySet* extractEditingProperties( + const StylePropertySet* style, + EditingStyle::PropertiesToInclude propertiesToInclude) { + if (!style) + return nullptr; + + switch (propertiesToInclude) { + case EditingStyle::AllProperties: + case EditingStyle::EditingPropertiesInEffect: + return copyEditingProperties(style, AllEditingProperties); + case EditingStyle::OnlyEditingInheritableProperties: + return copyEditingProperties(style, OnlyInheritableEditingProperties); + } + + NOTREACHED(); + return nullptr; +} + +void EditingStyle::mergeInlineAndImplicitStyleOfElement( + Element* element, + CSSPropertyOverrideMode mode, + PropertiesToInclude propertiesToInclude) { + EditingStyle* styleFromRules = EditingStyle::create(); + styleFromRules->mergeStyleFromRulesForSerialization(element); + + if (element->inlineStyle()) { + styleFromRules->m_mutableStyle->mergeAndOverrideOnConflict( + element->inlineStyle()); + } + + styleFromRules->m_mutableStyle = extractEditingProperties( + styleFromRules->m_mutableStyle.get(), propertiesToInclude); + mergeStyle(styleFromRules->m_mutableStyle.get(), mode); + + const HeapVector<Member<HTMLElementEquivalent>>& elementEquivalents = + htmlElementEquivalents(); + for (const auto& equivalent : elementEquivalents) { + if (elementMatchesAndPropertyIsNotInInlineStyleDecl( + equivalent.get(), element, mode, m_mutableStyle.get())) + equivalent->addToStyle(element, this); + } + + const HeapVector<Member<HTMLAttributeEquivalent>>& attributeEquivalents = + htmlAttributeEquivalents(); + for (const auto& attribute : attributeEquivalents) { + if (attribute->attributeName() == HTMLNames::dirAttr) + continue; // We don't want to include directionality + if (elementMatchesAndPropertyIsNotInInlineStyleDecl( + attribute.get(), element, mode, m_mutableStyle.get())) + attribute->addToStyle(element, this); + } +} + +EditingStyle* EditingStyle::wrappingStyleForAnnotatedSerialization( + ContainerNode* context) { + EditingStyle* wrappingStyle = + EditingStyle::create(context, EditingStyle::EditingPropertiesInEffect); + + // Styles that Mail blockquotes contribute should only be placed on the Mail + // blockquote, to help us differentiate those styles from ones that the user + // has applied. This helps us get the color of content pasted into + // blockquotes right. + wrappingStyle->removeStyleAddedByElement(toHTMLElement(enclosingNodeOfType( + firstPositionInOrBeforeNode(context), isMailHTMLBlockquoteElement, + CanCrossEditingBoundary))); + + // Call collapseTextDecorationProperties first or otherwise it'll copy the + // value over from in-effect to text-decorations. + wrappingStyle->collapseTextDecorationProperties(); + + return wrappingStyle; +} + +EditingStyle* EditingStyle::wrappingStyleForSerialization( + ContainerNode* context) { + DCHECK(context); + EditingStyle* wrappingStyle = EditingStyle::create(); + + // When not annotating for interchange, we only preserve inline style + // declarations. + for (Node& node : NodeTraversal::inclusiveAncestorsOf(*context)) { + if (node.isDocumentNode()) + break; + if (node.isStyledElement() && !isMailHTMLBlockquoteElement(&node)) { + wrappingStyle->mergeInlineAndImplicitStyleOfElement( + toElement(&node), EditingStyle::DoNotOverrideValues, + EditingStyle::EditingPropertiesInEffect); + } + } + + return wrappingStyle; +} + +static const CSSValueList& mergeTextDecorationValues( + const CSSValueList& mergedValue, + const CSSValueList& valueToMerge) { + DEFINE_STATIC_LOCAL(CSSIdentifierValue, underline, + (CSSIdentifierValue::create(CSSValueUnderline))); + DEFINE_STATIC_LOCAL(CSSIdentifierValue, lineThrough, + (CSSIdentifierValue::create(CSSValueLineThrough))); + CSSValueList& result = *mergedValue.copy(); + if (valueToMerge.hasValue(underline) && !mergedValue.hasValue(underline)) + result.append(underline); + + if (valueToMerge.hasValue(lineThrough) && !mergedValue.hasValue(lineThrough)) + result.append(lineThrough); + + return result; +} + +void EditingStyle::mergeStyle(const StylePropertySet* style, + CSSPropertyOverrideMode mode) { + if (!style) + return; + + if (!m_mutableStyle) { + m_mutableStyle = style->mutableCopy(); + return; + } + + unsigned propertyCount = style->propertyCount(); + for (unsigned i = 0; i < propertyCount; ++i) { + StylePropertySet::PropertyReference property = style->propertyAt(i); + const CSSValue* value = m_mutableStyle->getPropertyCSSValue(property.id()); + + // text decorations never override values + if ((property.id() == textDecorationPropertyForEditing() || + property.id() == CSSPropertyWebkitTextDecorationsInEffect) && + property.value().isValueList() && value) { + if (value->isValueList()) { + const CSSValueList& result = mergeTextDecorationValues( + *toCSSValueList(value), toCSSValueList(property.value())); + m_mutableStyle->setProperty(property.id(), result, + property.isImportant()); + continue; + } + // text-decoration: none is equivalent to not having the property + value = nullptr; + } + + if (mode == OverrideValues || (mode == DoNotOverrideValues && !value)) + m_mutableStyle->setProperty(property.toCSSProperty()); + } +} + +static MutableStylePropertySet* styleFromMatchedRulesForElement( + Element* element, + unsigned rulesToInclude) { + MutableStylePropertySet* style = + MutableStylePropertySet::create(HTMLQuirksMode); + StyleRuleList* matchedRules = + element->document().ensureStyleResolver().styleRulesForElement( + element, rulesToInclude); + if (matchedRules) { + for (unsigned i = 0; i < matchedRules->size(); ++i) + style->mergeAndOverrideOnConflict(&matchedRules->at(i)->properties()); + } + return style; +} + +void EditingStyle::mergeStyleFromRules(Element* element) { + MutableStylePropertySet* styleFromMatchedRules = + styleFromMatchedRulesForElement( + element, + StyleResolver::AuthorCSSRules | StyleResolver::CrossOriginCSSRules); + // Styles from the inline style declaration, held in the variable "style", + // take precedence over those from matched rules. + if (m_mutableStyle) + styleFromMatchedRules->mergeAndOverrideOnConflict(m_mutableStyle.get()); + + clear(); + m_mutableStyle = styleFromMatchedRules; +} + +void EditingStyle::mergeStyleFromRulesForSerialization(Element* element) { + mergeStyleFromRules(element); + + // The property value, if it's a percentage, may not reflect the actual + // computed value. + // For example: style="height: 1%; overflow: visible;" in quirksmode + // FIXME: There are others like this, see <rdar://problem/5195123> Slashdot + // copy/paste fidelity problem + CSSComputedStyleDeclaration* computedStyleForElement = + CSSComputedStyleDeclaration::create(element); + MutableStylePropertySet* fromComputedStyle = + MutableStylePropertySet::create(HTMLQuirksMode); + { + unsigned propertyCount = m_mutableStyle->propertyCount(); + for (unsigned i = 0; i < propertyCount; ++i) { + StylePropertySet::PropertyReference property = + m_mutableStyle->propertyAt(i); + const CSSValue& value = property.value(); + if (!value.isPrimitiveValue()) + continue; + if (toCSSPrimitiveValue(value).isPercentage()) { + if (const CSSValue* computedPropertyValue = + computedStyleForElement->getPropertyCSSValue(property.id())) { + fromComputedStyle->addRespectingCascade( + CSSProperty(property.id(), *computedPropertyValue)); + } + } + } + } + m_mutableStyle->mergeAndOverrideOnConflict(fromComputedStyle); +} + +static void removePropertiesInStyle( + MutableStylePropertySet* styleToRemovePropertiesFrom, + StylePropertySet* style) { + unsigned propertyCount = style->propertyCount(); + Vector<CSSPropertyID> propertiesToRemove(propertyCount); + for (unsigned i = 0; i < propertyCount; ++i) + propertiesToRemove[i] = style->propertyAt(i).id(); + + styleToRemovePropertiesFrom->removePropertiesInSet(propertiesToRemove.data(), + propertiesToRemove.size()); +} + +void EditingStyle::removeStyleFromRulesAndContext(Element* element, + ContainerNode* context) { + DCHECK(element); + if (!m_mutableStyle) + return; + + // StyleResolver requires clean style. + DCHECK_GE(element->document().lifecycle().state(), + DocumentLifecycle::StyleClean); + DCHECK(element->document().isActive()); + + // 1. Remove style from matched rules because style remain without repeating + // it in inline style declaration + MutableStylePropertySet* styleFromMatchedRules = + styleFromMatchedRulesForElement(element, + StyleResolver::AllButEmptyCSSRules); + if (styleFromMatchedRules && !styleFromMatchedRules->isEmpty()) { + m_mutableStyle = + getPropertiesNotIn(m_mutableStyle.get(), + styleFromMatchedRules->ensureCSSStyleDeclaration()); + } + + // 2. Remove style present in context and not overriden by matched rules. + EditingStyle* computedStyle = + EditingStyle::create(context, EditingPropertiesInEffect); + if (computedStyle->m_mutableStyle) { + if (!computedStyle->m_mutableStyle->getPropertyCSSValue( + CSSPropertyBackgroundColor)) { + computedStyle->m_mutableStyle->setProperty(CSSPropertyBackgroundColor, + CSSValueTransparent); + } + + removePropertiesInStyle(computedStyle->m_mutableStyle.get(), + styleFromMatchedRules); + m_mutableStyle = getPropertiesNotIn( + m_mutableStyle.get(), + computedStyle->m_mutableStyle->ensureCSSStyleDeclaration()); + } + + // 3. If this element is a span and has display: inline or float: none, remove + // them unless they are overriden by rules. These rules are added by + // serialization code to wrap text nodes. + if (isStyleSpanOrSpanWithOnlyStyleAttribute(element)) { + if (!styleFromMatchedRules->getPropertyCSSValue(CSSPropertyDisplay) && + getIdentifierValue(m_mutableStyle.get(), CSSPropertyDisplay) == + CSSValueInline) + m_mutableStyle->removeProperty(CSSPropertyDisplay); + if (!styleFromMatchedRules->getPropertyCSSValue(CSSPropertyFloat) && + getIdentifierValue(m_mutableStyle.get(), CSSPropertyFloat) == + CSSValueNone) + m_mutableStyle->removeProperty(CSSPropertyFloat); + } +} + +void EditingStyle::removePropertiesInElementDefaultStyle(Element* element) { + if (!m_mutableStyle || m_mutableStyle->isEmpty()) + return; + + StylePropertySet* defaultStyle = styleFromMatchedRulesForElement( + element, StyleResolver::UAAndUserCSSRules); + + removePropertiesInStyle(m_mutableStyle.get(), defaultStyle); +} + +void EditingStyle::addAbsolutePositioningFromElement(const Element& element) { + LayoutRect rect = element.boundingBox(); + LayoutObject* layoutObject = element.layoutObject(); + + LayoutUnit x = rect.x(); + LayoutUnit y = rect.y(); + LayoutUnit width = rect.width(); + LayoutUnit height = rect.height(); + if (layoutObject && layoutObject->isBox()) { + LayoutBox* layoutBox = toLayoutBox(layoutObject); + + x -= layoutBox->marginLeft(); + y -= layoutBox->marginTop(); + + m_mutableStyle->setProperty(CSSPropertyBoxSizing, CSSValueBorderBox); + } + + m_mutableStyle->setProperty(CSSPropertyPosition, CSSValueAbsolute); + m_mutableStyle->setProperty( + CSSPropertyLeft, + *CSSPrimitiveValue::create(x, CSSPrimitiveValue::UnitType::Pixels)); + m_mutableStyle->setProperty( + CSSPropertyTop, + *CSSPrimitiveValue::create(y, CSSPrimitiveValue::UnitType::Pixels)); + m_mutableStyle->setProperty( + CSSPropertyWidth, + *CSSPrimitiveValue::create(width, CSSPrimitiveValue::UnitType::Pixels)); + m_mutableStyle->setProperty( + CSSPropertyHeight, + *CSSPrimitiveValue::create(height, CSSPrimitiveValue::UnitType::Pixels)); +} + +void EditingStyle::forceInline() { + if (!m_mutableStyle) + m_mutableStyle = MutableStylePropertySet::create(HTMLQuirksMode); + const bool propertyIsImportant = true; + m_mutableStyle->setProperty(CSSPropertyDisplay, CSSValueInline, + propertyIsImportant); +} + +int EditingStyle::legacyFontSize(Document* document) const { + const CSSValue* cssValue = + m_mutableStyle->getPropertyCSSValue(CSSPropertyFontSize); + if (!cssValue || + !(cssValue->isPrimitiveValue() || cssValue->isIdentifierValue())) + return 0; + return legacyFontSizeFromCSSValue(document, cssValue, m_isMonospaceFont, + AlwaysUseLegacyFontSize); +} + +EditingStyle* EditingStyle::styleAtSelectionStart( + const VisibleSelection& selection, + bool shouldUseBackgroundColorInEffect, + MutableStylePropertySet* styleToCheck) { + if (selection.isNone()) + return nullptr; + + Document& document = *selection.start().document(); + + DCHECK(!document.needsLayoutTreeUpdate()); + DocumentLifecycle::DisallowTransitionScope disallowTransition( + document.lifecycle()); + + Position position = adjustedSelectionStartForStyleComputation(selection); + + // If the pos is at the end of a text node, then this node is not fully + // selected. Move it to the next deep equivalent position to avoid removing + // the style from this node. + // e.g. if pos was at Position("hello", 5) in <b>hello<div>world</div></b>, we + // want Position("world", 0) instead. + // We only do this for range because caret at Position("hello", 5) in + // <b>hello</b>world should give you font-weight: bold. + Node* positionNode = position.computeContainerNode(); + if (selection.isRange() && positionNode && positionNode->isTextNode() && + position.computeOffsetInContainerNode() == + positionNode->maxCharacterOffset()) + position = nextVisuallyDistinctCandidate(position); + + Element* element = associatedElementOf(position); + if (!element) + return nullptr; + + EditingStyle* style = + EditingStyle::create(element, EditingStyle::AllProperties); + style->mergeTypingStyle(&element->document()); + + // If |element| has <sub> or <sup> ancestor element, apply the corresponding + // style(vertical-align) to it so that document.queryCommandState() works with + // the style. See bug http://crbug.com/582225. + CSSValueID valueID = + getIdentifierValue(styleToCheck, CSSPropertyVerticalAlign); + if (valueID == CSSValueSub || valueID == CSSValueSuper) { + CSSComputedStyleDeclaration* elementStyle = + CSSComputedStyleDeclaration::create(element); + // Find the ancestor that has CSSValueSub or CSSValueSuper as the value of + // CSS vertical-align property. + if (getIdentifierValue(elementStyle, CSSPropertyVerticalAlign) == + CSSValueBaseline && + hasAncestorVerticalAlignStyle(*element, valueID)) + style->m_mutableStyle->setProperty(CSSPropertyVerticalAlign, valueID); + } + + // If background color is transparent, traverse parent nodes until we hit a + // different value or document root Also, if the selection is a range, ignore + // the background color at the start of selection, and find the background + // color of the common ancestor. + if (shouldUseBackgroundColorInEffect && + (selection.isRange() || + hasTransparentBackgroundColor(style->m_mutableStyle.get()))) { + const EphemeralRange range(selection.toNormalizedEphemeralRange()); + if (const CSSValue* value = + backgroundColorValueInEffect(Range::commonAncestorContainer( + range.startPosition().computeContainerNode(), + range.endPosition().computeContainerNode()))) + style->setProperty(CSSPropertyBackgroundColor, value->cssText()); + } + + return style; +} + +static bool isUnicodeBidiNestedOrMultipleEmbeddings(CSSValueID valueID) { + return valueID == CSSValueEmbed || valueID == CSSValueBidiOverride || + valueID == CSSValueWebkitIsolate || + valueID == CSSValueWebkitIsolateOverride || + valueID == CSSValueWebkitPlaintext || valueID == CSSValueIsolate || + valueID == CSSValueIsolateOverride || valueID == CSSValuePlaintext; +} + +WritingDirection EditingStyle::textDirectionForSelection( + const VisibleSelection& selection, + EditingStyle* typingStyle, + bool& hasNestedOrMultipleEmbeddings) { + hasNestedOrMultipleEmbeddings = true; + + if (selection.isNone()) + return NaturalWritingDirection; + + Position position = mostForwardCaretPosition(selection.start()); + + Node* node = position.anchorNode(); + if (!node) + return NaturalWritingDirection; + + Position end; + if (selection.isRange()) { + end = mostBackwardCaretPosition(selection.end()); + + DCHECK(end.document()); + const EphemeralRange caretRange(position.parentAnchoredEquivalent(), + end.parentAnchoredEquivalent()); + for (Node& n : caretRange.nodes()) { + if (!n.isStyledElement()) + continue; + + CSSComputedStyleDeclaration* style = + CSSComputedStyleDeclaration::create(&n); + const CSSValue* unicodeBidi = + style->getPropertyCSSValue(CSSPropertyUnicodeBidi); + if (!unicodeBidi || !unicodeBidi->isIdentifierValue()) + continue; + + CSSValueID unicodeBidiValue = + toCSSIdentifierValue(unicodeBidi)->getValueID(); + if (isUnicodeBidiNestedOrMultipleEmbeddings(unicodeBidiValue)) + return NaturalWritingDirection; + } + } + + if (selection.isCaret()) { + WritingDirection direction; + if (typingStyle && typingStyle->textDirection(direction)) { + hasNestedOrMultipleEmbeddings = false; + return direction; + } + node = selection.visibleStart().deepEquivalent().anchorNode(); + } + DCHECK(node); + + // The selection is either a caret with no typing attributes or a range in + // which no embedding is added, so just use the start position to decide. + Node* block = enclosingBlock(node); + WritingDirection foundDirection = NaturalWritingDirection; + + for (Node& runner : NodeTraversal::inclusiveAncestorsOf(*node)) { + if (runner == block) + break; + if (!runner.isStyledElement()) + continue; + + Element* element = &toElement(runner); + CSSComputedStyleDeclaration* style = + CSSComputedStyleDeclaration::create(element); + const CSSValue* unicodeBidi = + style->getPropertyCSSValue(CSSPropertyUnicodeBidi); + if (!unicodeBidi || !unicodeBidi->isIdentifierValue()) + continue; + + CSSValueID unicodeBidiValue = + toCSSIdentifierValue(unicodeBidi)->getValueID(); + if (unicodeBidiValue == CSSValueNormal) + continue; + + if (unicodeBidiValue == CSSValueBidiOverride) + return NaturalWritingDirection; + + DCHECK(isEmbedOrIsolate(unicodeBidiValue)) << unicodeBidiValue; + const CSSValue* direction = + style->getPropertyCSSValue(CSSPropertyDirection); + if (!direction || !direction->isIdentifierValue()) + continue; + + int directionValue = toCSSIdentifierValue(direction)->getValueID(); + if (directionValue != CSSValueLtr && directionValue != CSSValueRtl) + continue; + + if (foundDirection != NaturalWritingDirection) + return NaturalWritingDirection; + + // In the range case, make sure that the embedding element persists until + // the end of the range. + if (selection.isRange() && !end.anchorNode()->isDescendantOf(element)) + return NaturalWritingDirection; + + foundDirection = directionValue == CSSValueLtr + ? LeftToRightWritingDirection + : RightToLeftWritingDirection; + } + hasNestedOrMultipleEmbeddings = false; + return foundDirection; +} + +DEFINE_TRACE(EditingStyle) { + visitor->trace(m_mutableStyle); +} + +static void reconcileTextDecorationProperties(MutableStylePropertySet* style) { + const CSSValue* textDecorationsInEffect = + style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect); + const CSSValue* textDecoration = + style->getPropertyCSSValue(textDecorationPropertyForEditing()); + // "LayoutTests/editing/execCommand/insert-list-and-strikethrough.html" makes + // both |textDecorationsInEffect| and |textDecoration| non-null. + if (textDecorationsInEffect) { + style->setProperty(textDecorationPropertyForEditing(), + textDecorationsInEffect->cssText()); + style->removeProperty(CSSPropertyWebkitTextDecorationsInEffect); + textDecoration = textDecorationsInEffect; + } + + // If text-decoration is set to "none", remove the property because we don't + // want to add redundant "text-decoration: none". + if (textDecoration && !textDecoration->isValueList()) + style->removeProperty(textDecorationPropertyForEditing()); +} + +StyleChange::StyleChange(EditingStyle* style, const Position& position) + : m_applyBold(false), + m_applyItalic(false), + m_applyUnderline(false), + m_applyLineThrough(false), + m_applySubscript(false), + m_applySuperscript(false) { + Document* document = position.document(); + if (!style || !style->style() || !document || !document->frame() || + !associatedElementOf(position)) + return; + + CSSComputedStyleDeclaration* computedStyle = ensureComputedStyle(position); + // FIXME: take care of background-color in effect + MutableStylePropertySet* mutableStyle = + getPropertiesNotIn(style->style(), computedStyle); + DCHECK(mutableStyle); + + reconcileTextDecorationProperties(mutableStyle); + if (!document->frame()->editor().shouldStyleWithCSS()) + extractTextStyles(document, mutableStyle, computedStyle->isMonospaceFont()); + + // Changing the whitespace style in a tab span would collapse the tab into a + // space. + if (isTabHTMLSpanElementTextNode(position.anchorNode()) || + isTabHTMLSpanElement((position.anchorNode()))) + mutableStyle->removeProperty(CSSPropertyWhiteSpace); + + // If unicode-bidi is present in mutableStyle and direction is not, then add + // direction to mutableStyle. + // FIXME: Shouldn't this be done in getPropertiesNotIn? + if (mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi) && + !style->style()->getPropertyCSSValue(CSSPropertyDirection)) { + mutableStyle->setProperty( + CSSPropertyDirection, + style->style()->getPropertyValue(CSSPropertyDirection)); + } + + // Save the result for later + m_cssStyle = mutableStyle->asText().stripWhiteSpace(); +} + +static void setTextDecorationProperty(MutableStylePropertySet* style, + const CSSValueList* newTextDecoration, + CSSPropertyID propertyID) { + if (newTextDecoration->length()) { + style->setProperty(propertyID, newTextDecoration->cssText(), + style->propertyIsImportant(propertyID)); + } else { + // text-decoration: none is redundant since it does not remove any text + // decorations. + style->removeProperty(propertyID); + } +} + +void StyleChange::extractTextStyles(Document* document, + MutableStylePropertySet* style, + bool isMonospaceFont) { + DCHECK(style); + + if (getIdentifierValue(style, CSSPropertyFontWeight) == CSSValueBold) { + style->removeProperty(CSSPropertyFontWeight); + m_applyBold = true; + } + + int fontStyle = getIdentifierValue(style, CSSPropertyFontStyle); + if (fontStyle == CSSValueItalic || fontStyle == CSSValueOblique) { + style->removeProperty(CSSPropertyFontStyle); + m_applyItalic = true; + } + + // Assuming reconcileTextDecorationProperties has been called, there should + // not be -webkit-text-decorations-in-effect + // Furthermore, text-decoration: none has been trimmed so that text-decoration + // property is always a CSSValueList. + const CSSValue* textDecoration = + style->getPropertyCSSValue(textDecorationPropertyForEditing()); + if (textDecoration && textDecoration->isValueList()) { + DEFINE_STATIC_LOCAL(CSSIdentifierValue, underline, + (CSSIdentifierValue::create(CSSValueUnderline))); + DEFINE_STATIC_LOCAL(CSSIdentifierValue, lineThrough, + (CSSIdentifierValue::create(CSSValueLineThrough))); + CSSValueList* newTextDecoration = toCSSValueList(textDecoration)->copy(); + if (newTextDecoration->removeAll(underline)) + m_applyUnderline = true; + if (newTextDecoration->removeAll(lineThrough)) + m_applyLineThrough = true; + + // If trimTextDecorations, delete underline and line-through + setTextDecorationProperty(style, newTextDecoration, + textDecorationPropertyForEditing()); + } + + int verticalAlign = getIdentifierValue(style, CSSPropertyVerticalAlign); + switch (verticalAlign) { + case CSSValueSub: + style->removeProperty(CSSPropertyVerticalAlign); + m_applySubscript = true; + break; + case CSSValueSuper: + style->removeProperty(CSSPropertyVerticalAlign); + m_applySuperscript = true; + break; + } + + if (style->getPropertyCSSValue(CSSPropertyColor)) { + m_applyFontColor = getFontColor(style).serialized(); + style->removeProperty(CSSPropertyColor); + } + + m_applyFontFace = style->getPropertyValue(CSSPropertyFontFamily); + // Remove double quotes for Outlook 2007 compatibility. See + // https://bugs.webkit.org/show_bug.cgi?id=79448 + m_applyFontFace.replace('"', ""); + style->removeProperty(CSSPropertyFontFamily); + + if (const CSSValue* fontSize = + style->getPropertyCSSValue(CSSPropertyFontSize)) { + if (!fontSize->isPrimitiveValue() && !fontSize->isIdentifierValue()) { + // Can't make sense of the number. Put no font size. + style->removeProperty(CSSPropertyFontSize); + } else if (int legacyFontSize = legacyFontSizeFromCSSValue( + document, fontSize, isMonospaceFont, + UseLegacyFontSizeOnlyIfPixelValuesMatch)) { + m_applyFontSize = String::number(legacyFontSize); + style->removeProperty(CSSPropertyFontSize); + } + } +} + +static void diffTextDecorations(MutableStylePropertySet* style, + CSSPropertyID propertyID, + const CSSValue* refTextDecoration) { + const CSSValue* textDecoration = style->getPropertyCSSValue(propertyID); + if (!textDecoration || !textDecoration->isValueList() || !refTextDecoration || + !refTextDecoration->isValueList()) + return; + + CSSValueList* newTextDecoration = toCSSValueList(textDecoration)->copy(); + const CSSValueList* valuesInRefTextDecoration = + toCSSValueList(refTextDecoration); + + for (size_t i = 0; i < valuesInRefTextDecoration->length(); i++) + newTextDecoration->removeAll(valuesInRefTextDecoration->item(i)); + + setTextDecorationProperty(style, newTextDecoration, propertyID); +} + +static bool fontWeightIsBold(const CSSValue* fontWeight) { + if (!fontWeight->isIdentifierValue()) + return false; + + // Because b tag can only bold text, there are only two states in plain html: + // bold and not bold. Collapse all other values to either one of these two + // states for editing purposes. + switch (toCSSIdentifierValue(fontWeight)->getValueID()) { + case CSSValue100: + case CSSValue200: + case CSSValue300: + case CSSValue400: + case CSSValue500: + case CSSValueNormal: + return false; + case CSSValueBold: + case CSSValue600: + case CSSValue700: + case CSSValue800: + case CSSValue900: + return true; + default: + break; + } + + NOTREACHED(); // For CSSValueBolder and CSSValueLighter + return false; +} + +static bool fontWeightNeedsResolving(const CSSValue* fontWeight) { + if (!fontWeight->isIdentifierValue()) + return true; + + const CSSValueID value = toCSSIdentifierValue(fontWeight)->getValueID(); + return value == CSSValueLighter || value == CSSValueBolder; +} + +MutableStylePropertySet* getPropertiesNotIn( + StylePropertySet* styleWithRedundantProperties, + CSSStyleDeclaration* baseStyle) { + DCHECK(styleWithRedundantProperties); + DCHECK(baseStyle); + MutableStylePropertySet* result = styleWithRedundantProperties->mutableCopy(); + + result->removeEquivalentProperties(baseStyle); + + const CSSValue* baseTextDecorationsInEffect = + baseStyle->getPropertyCSSValueInternal( + CSSPropertyWebkitTextDecorationsInEffect); + diffTextDecorations(result, textDecorationPropertyForEditing(), + baseTextDecorationsInEffect); + diffTextDecorations(result, CSSPropertyWebkitTextDecorationsInEffect, + baseTextDecorationsInEffect); + + if (const CSSValue* baseFontWeight = + baseStyle->getPropertyCSSValueInternal(CSSPropertyFontWeight)) { + if (const CSSValue* fontWeight = + result->getPropertyCSSValue(CSSPropertyFontWeight)) { + if (!fontWeightNeedsResolving(fontWeight) && + !fontWeightNeedsResolving(baseFontWeight) && + (fontWeightIsBold(fontWeight) == fontWeightIsBold(baseFontWeight))) + result->removeProperty(CSSPropertyFontWeight); + } + } + + if (baseStyle->getPropertyCSSValueInternal(CSSPropertyColor) && + getFontColor(result) == getFontColor(baseStyle)) + result->removeProperty(CSSPropertyColor); + + if (baseStyle->getPropertyCSSValueInternal(CSSPropertyTextAlign) && + textAlignResolvingStartAndEnd(result) == + textAlignResolvingStartAndEnd(baseStyle)) + result->removeProperty(CSSPropertyTextAlign); + + if (baseStyle->getPropertyCSSValueInternal(CSSPropertyBackgroundColor) && + getBackgroundColor(result) == getBackgroundColor(baseStyle)) + result->removeProperty(CSSPropertyBackgroundColor); + + return result; +} + +CSSValueID getIdentifierValue(StylePropertySet* style, + CSSPropertyID propertyID) { + if (!style) + return CSSValueInvalid; + const CSSValue* value = style->getPropertyCSSValue(propertyID); + if (!value || !value->isIdentifierValue()) + return CSSValueInvalid; + return toCSSIdentifierValue(value)->getValueID(); +} + +CSSValueID getIdentifierValue(CSSStyleDeclaration* style, + CSSPropertyID propertyID) { + if (!style) + return CSSValueInvalid; + const CSSValue* value = style->getPropertyCSSValueInternal(propertyID); + if (!value || !value->isIdentifierValue()) + return CSSValueInvalid; + return toCSSIdentifierValue(value)->getValueID(); +} + +int legacyFontSizeFromCSSValue(Document* document, + const CSSValue* value, + bool isMonospaceFont, + LegacyFontSizeMode mode) { + if (value->isPrimitiveValue()) { + const CSSPrimitiveValue& primitiveValue = toCSSPrimitiveValue(*value); + CSSPrimitiveValue::LengthUnitType lengthType; + if (CSSPrimitiveValue::unitTypeToLengthUnitType( + primitiveValue.typeWithCalcResolved(), lengthType) && + lengthType == CSSPrimitiveValue::UnitTypePixels) { + double conversion = + CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor( + primitiveValue.typeWithCalcResolved()); + int pixelFontSize = + clampTo<int>(primitiveValue.getDoubleValue() * conversion); + int legacyFontSize = + FontSize::legacyFontSize(document, pixelFontSize, isMonospaceFont); + // Use legacy font size only if pixel value matches exactly to that of + // legacy font size. + if (mode == AlwaysUseLegacyFontSize || + FontSize::fontSizeForKeyword(document, legacyFontSize, + isMonospaceFont) == pixelFontSize) + return legacyFontSize; + + return 0; + } + } + + if (value->isIdentifierValue()) { + const CSSIdentifierValue& identifierValue = toCSSIdentifierValue(*value); + if (CSSValueXSmall <= identifierValue.getValueID() && + identifierValue.getValueID() <= CSSValueWebkitXxxLarge) + return identifierValue.getValueID() - CSSValueXSmall + 1; + } + + return 0; +} + +bool isTransparentColorValue(const CSSValue* cssValue) { + if (!cssValue) + return true; + if (cssValue->isColorValue()) + return !toCSSColorValue(cssValue)->value().alpha(); + if (!cssValue->isIdentifierValue()) + return false; + return toCSSIdentifierValue(cssValue)->getValueID() == CSSValueTransparent; +} + +bool hasTransparentBackgroundColor(CSSStyleDeclaration* style) { + const CSSValue* cssValue = + style->getPropertyCSSValueInternal(CSSPropertyBackgroundColor); + return isTransparentColorValue(cssValue); +} + +bool hasTransparentBackgroundColor(StylePropertySet* style) { + const CSSValue* cssValue = + style->getPropertyCSSValue(CSSPropertyBackgroundColor); + return isTransparentColorValue(cssValue); +} + +const CSSValue* backgroundColorValueInEffect(Node* node) { + for (Node* ancestor = node; ancestor; ancestor = ancestor->parentNode()) { + CSSComputedStyleDeclaration* ancestorStyle = + CSSComputedStyleDeclaration::create(ancestor); + if (!hasTransparentBackgroundColor(ancestorStyle)) + return ancestorStyle->getPropertyCSSValue(CSSPropertyBackgroundColor); + } + return nullptr; +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/EditingStyleUtilities.h b/third_party/WebKit/Source/core/editing/EditingStyleUtilities.h new file mode 100644 index 0000000..6c8d53a0 --- /dev/null +++ b/third_party/WebKit/Source/core/editing/EditingStyleUtilities.h
@@ -0,0 +1,278 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2013 Apple 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. + */ + +#ifndef EditingStyleUtilities_h +#define EditingStyleUtilities_h + +#include "core/CSSPropertyNames.h" +#include "core/CSSValueKeywords.h" +#include "core/CoreExport.h" +#include "core/editing/Position.h" +#include "core/editing/VisibleSelection.h" +#include "core/editing/WritingDirection.h" +#include "platform/heap/Handle.h" +#include "wtf/Forward.h" +#include "wtf/TriState.h" +#include "wtf/Vector.h" +#include "wtf/text/WTFString.h" + +namespace blink { + +class CSSStyleDeclaration; +class CSSComputedStyleDeclaration; +class ContainerNode; +class Document; +class Element; +class HTMLElement; +class MutableStylePropertySet; +class Node; +class QualifiedName; +class ComputedStyle; +class StylePropertySet; + +class CORE_EXPORT EditingStyle final : public GarbageCollected<EditingStyle> { + public: + enum PropertiesToInclude { + AllProperties, + OnlyEditingInheritableProperties, + EditingPropertiesInEffect + }; + enum ShouldPreserveWritingDirection { + PreserveWritingDirection, + DoNotPreserveWritingDirection + }; + enum ShouldExtractMatchingStyle { + ExtractMatchingStyle, + DoNotExtractMatchingStyle + }; + static float NoFontDelta; + + static EditingStyle* create() { return new EditingStyle(); } + + static EditingStyle* create(ContainerNode* node, + PropertiesToInclude propertiesToInclude = + OnlyEditingInheritableProperties) { + return new EditingStyle(node, propertiesToInclude); + } + + static EditingStyle* create(const Position& position, + PropertiesToInclude propertiesToInclude = + OnlyEditingInheritableProperties) { + return new EditingStyle(position, propertiesToInclude); + } + + static EditingStyle* create(const StylePropertySet* style) { + return new EditingStyle(style); + } + + static EditingStyle* create(CSSPropertyID propertyID, const String& value) { + return new EditingStyle(propertyID, value); + } + + MutableStylePropertySet* style() { return m_mutableStyle.get(); } + bool textDirection(WritingDirection&) const; + bool isEmpty() const; + void overrideWithStyle(const StylePropertySet*); + void clear(); + EditingStyle* copy() const; + EditingStyle* extractAndRemoveBlockProperties(); + EditingStyle* extractAndRemoveTextDirection(); + void removeBlockProperties(); + void removeStyleAddedByElement(Element*); + void removeStyleConflictingWithStyleOfElement(Element*); + void collapseTextDecorationProperties(); + enum ShouldIgnoreTextOnlyProperties { + IgnoreTextOnlyProperties, + DoNotIgnoreTextOnlyProperties + }; + TriState triStateOfStyle(EditingStyle*) const; + TriState triStateOfStyle(const VisibleSelection&) const; + bool conflictsWithInlineStyleOfElement(HTMLElement* element) const { + return conflictsWithInlineStyleOfElement(element, 0, 0); + } + bool conflictsWithInlineStyleOfElement( + HTMLElement* element, + EditingStyle* extractedStyle, + Vector<CSSPropertyID>& conflictingProperties) const { + return conflictsWithInlineStyleOfElement(element, extractedStyle, + &conflictingProperties); + } + bool conflictsWithImplicitStyleOfElement( + HTMLElement*, + EditingStyle* extractedStyle = nullptr, + ShouldExtractMatchingStyle = DoNotExtractMatchingStyle) const; + bool conflictsWithImplicitStyleOfAttributes(HTMLElement*) const; + bool extractConflictingImplicitStyleOfAttributes( + HTMLElement*, + ShouldPreserveWritingDirection, + EditingStyle* extractedStyle, + Vector<QualifiedName>& conflictingAttributes, + ShouldExtractMatchingStyle) const; + bool styleIsPresentInComputedStyleOfNode(Node*) const; + + static bool elementIsStyledSpanOrHTMLEquivalent(const HTMLElement*); + + void prepareToApplyAt( + const Position&, + ShouldPreserveWritingDirection = DoNotPreserveWritingDirection); + void mergeTypingStyle(Document*); + enum CSSPropertyOverrideMode { OverrideValues, DoNotOverrideValues }; + void mergeInlineStyleOfElement(HTMLElement*, + CSSPropertyOverrideMode, + PropertiesToInclude = AllProperties); + static EditingStyle* wrappingStyleForAnnotatedSerialization( + ContainerNode* context); + static EditingStyle* wrappingStyleForSerialization(ContainerNode* context); + void mergeStyleFromRules(Element*); + void mergeStyleFromRulesForSerialization(Element*); + void removeStyleFromRulesAndContext(Element*, ContainerNode* context); + void removePropertiesInElementDefaultStyle(Element*); + void addAbsolutePositioningFromElement(const Element&); + void forceInline(); + int legacyFontSize(Document*) const; + + float fontSizeDelta() const { return m_fontSizeDelta; } + bool hasFontSizeDelta() const { return m_fontSizeDelta != NoFontDelta; } + + static EditingStyle* styleAtSelectionStart( + const VisibleSelection&, + bool shouldUseBackgroundColorInEffect = false, + MutableStylePropertySet* styleToCheck = nullptr); + static WritingDirection textDirectionForSelection( + const VisibleSelection&, + EditingStyle* typingStyle, + bool& hasNestedOrMultipleEmbeddings); + static bool isEmbedOrIsolate(CSSValueID unicodeBidi) { + return unicodeBidi == CSSValueIsolate || + unicodeBidi == CSSValueWebkitIsolate || unicodeBidi == CSSValueEmbed; + } + + DECLARE_TRACE(); + + private: + EditingStyle() = default; + EditingStyle(ContainerNode*, PropertiesToInclude); + EditingStyle(const Position&, PropertiesToInclude); + explicit EditingStyle(const StylePropertySet*); + EditingStyle(CSSPropertyID, const String& value); + void init(Node*, PropertiesToInclude); + void removeInheritedColorsIfNeeded(const ComputedStyle*); + void setProperty(CSSPropertyID, const String& value, bool important = false); + void replaceFontSizeByKeywordIfPossible(const ComputedStyle*, + CSSComputedStyleDeclaration*); + void extractFontSizeDelta(); + TriState triStateOfStyle(CSSStyleDeclaration* styleToCompare, + ShouldIgnoreTextOnlyProperties) const; + bool conflictsWithInlineStyleOfElement( + HTMLElement*, + EditingStyle* extractedStyle, + Vector<CSSPropertyID>* conflictingProperties) const; + void mergeInlineAndImplicitStyleOfElement(Element*, + CSSPropertyOverrideMode, + PropertiesToInclude); + void mergeStyle(const StylePropertySet*, CSSPropertyOverrideMode); + + Member<MutableStylePropertySet> m_mutableStyle; + bool m_isMonospaceFont = false; + float m_fontSizeDelta = NoFontDelta; + bool m_isVerticalAlign = false; + + friend class HTMLElementEquivalent; + friend class HTMLAttributeEquivalent; +}; + +class StyleChange { + DISALLOW_NEW(); + + public: + StyleChange() + : m_applyBold(false), + m_applyItalic(false), + m_applyUnderline(false), + m_applyLineThrough(false), + m_applySubscript(false), + m_applySuperscript(false) {} + + StyleChange(EditingStyle*, const Position&); + + String cssStyle() const { return m_cssStyle; } + bool applyBold() const { return m_applyBold; } + bool applyItalic() const { return m_applyItalic; } + bool applyUnderline() const { return m_applyUnderline; } + bool applyLineThrough() const { return m_applyLineThrough; } + bool applySubscript() const { return m_applySubscript; } + bool applySuperscript() const { return m_applySuperscript; } + bool applyFontColor() const { return m_applyFontColor.length() > 0; } + bool applyFontFace() const { return m_applyFontFace.length() > 0; } + bool applyFontSize() const { return m_applyFontSize.length() > 0; } + + String fontColor() { return m_applyFontColor; } + String fontFace() { return m_applyFontFace; } + String fontSize() { return m_applyFontSize; } + + bool operator==(const StyleChange& other) { + return m_cssStyle == other.m_cssStyle && m_applyBold == other.m_applyBold && + m_applyItalic == other.m_applyItalic && + m_applyUnderline == other.m_applyUnderline && + m_applyLineThrough == other.m_applyLineThrough && + m_applySubscript == other.m_applySubscript && + m_applySuperscript == other.m_applySuperscript && + m_applyFontColor == other.m_applyFontColor && + m_applyFontFace == other.m_applyFontFace && + m_applyFontSize == other.m_applyFontSize; + } + bool operator!=(const StyleChange& other) { return !(*this == other); } + + private: + void extractTextStyles(Document*, + MutableStylePropertySet*, + bool isMonospaceFont); + + String m_cssStyle; + bool m_applyBold; + bool m_applyItalic; + bool m_applyUnderline; + bool m_applyLineThrough; + bool m_applySubscript; + bool m_applySuperscript; + String m_applyFontColor; + String m_applyFontFace; + String m_applyFontSize; +}; + +// FIXME: Remove these functions or make them non-global to discourage using +// CSSStyleDeclaration directly. +CSSValueID getIdentifierValue(CSSStyleDeclaration*, CSSPropertyID); +CSSValueID getIdentifierValue(StylePropertySet*, CSSPropertyID); + +} // namespace blink + +#endif // EditingStyleUtilities_h
diff --git a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp index 3ca0cfd..73f1e723 100644 --- a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp +++ b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
@@ -379,9 +379,9 @@ DCHECK(node->document().isActive()); if (node->document().lifecycle().state() >= DocumentLifecycle::InStyleRecalc) { - // TODO(yosin): Once we change |LayoutObject::adjustStyleDifference()| - // not to call |FrameSelection::hasCaret()|, we should not assume - // calling |isEditablePosition()| in |InStyleRecalc| is safe. + // TODO(yosin): Update the condition and DCHECK here given that + // https://codereview.chromium.org/2665823002/ avoided this function from + // being called during InStyleRecalc. } else { DCHECK(!needsLayoutTreeUpdate(position)) << position; }
diff --git a/third_party/WebKit/Source/core/editing/Editor.cpp b/third_party/WebKit/Source/core/editing/Editor.cpp index ac351ac..717611d 100644 --- a/third_party/WebKit/Source/core/editing/Editor.cpp +++ b/third_party/WebKit/Source/core/editing/Editor.cpp
@@ -1623,7 +1623,6 @@ const Position& oldSelectionStart, FrameSelection::SetSelectionOptions options) { spellChecker().respondToChangedSelection(oldSelectionStart, options); - frame().inputMethodController().cancelCompositionIfSelectionIsInvalid(); client().respondToChangedSelection(&frame(), frame().selection().getSelectionType()); setStartNewKillRingSequence(true);
diff --git a/third_party/WebKit/Source/core/editing/FrameCaret.cpp b/third_party/WebKit/Source/core/editing/FrameCaret.cpp index 2c1d4f3..002f3f74 100644 --- a/third_party/WebKit/Source/core/editing/FrameCaret.cpp +++ b/third_party/WebKit/Source/core/editing/FrameCaret.cpp
@@ -39,7 +39,6 @@ #include "core/layout/LayoutTheme.h" #include "core/layout/api/LayoutPartItem.h" #include "core/page/Page.h" -#include "core/paint/PaintLayer.h" #include "public/platform/WebTraceLocation.h" namespace blink { @@ -50,11 +49,9 @@ m_frame(frame), m_caretBase(new CaretDisplayItemClient()), m_caretVisibility(CaretVisibility::Hidden), - m_previousCaretVisibility(CaretVisibility::Hidden), m_caretBlinkTimer(TaskRunnerHelper::get(TaskType::UnspecedTimer, &frame), this, &FrameCaret::caretBlinkTimerFired), - m_caretRectDirty(true), m_shouldPaintCaret(true), m_isCaretBlinkingSuspended(false), m_shouldShowBlockCursor(false) {} @@ -64,13 +61,10 @@ DEFINE_TRACE(FrameCaret) { visitor->trace(m_selectionEditor); visitor->trace(m_frame); - visitor->trace(m_previousCaretNode); - visitor->trace(m_previousCaretAnchorNode); - SynchronousMutationObserver::trace(visitor); } -void FrameCaret::documentAttached(Document* document) { - setContext(document); +const DisplayItemClient& FrameCaret::displayItemClient() const { + return *m_caretBase; } const PositionWithAffinity FrameCaret::caretPosition() const { @@ -81,10 +75,6 @@ return PositionWithAffinity(selection.start(), selection.affinity()); } -const DisplayItemClient& FrameCaret::displayItemClient() const { - return *m_caretBase; -} - inline static bool shouldStopBlinkingDueToTypingCommand(LocalFrame* frame) { return frame->editor().lastEditCommand() && frame->editor().lastEditCommand()->shouldStopCaretBlinking(); @@ -121,7 +111,7 @@ void FrameCaret::stopCaretBlinkTimer() { if (m_caretBlinkTimer.isActive() || m_shouldPaintCaret) - setCaretRectNeedsUpdate(); + scheduleVisualUpdateForPaintInvalidationIfNeeded(); m_shouldPaintCaret = false; m_caretBlinkTimer.stop(); } @@ -136,7 +126,7 @@ m_caretBlinkTimer.startRepeating(blinkInterval, BLINK_FROM_HERE); m_shouldPaintCaret = true; - setCaretRectNeedsUpdate(); + scheduleVisualUpdateForPaintInvalidationIfNeeded(); } void FrameCaret::setCaretVisibility(CaretVisibility visibility) { @@ -146,22 +136,31 @@ m_caretVisibility = visibility; updateAppearance(); + scheduleVisualUpdateForPaintInvalidationIfNeeded(); } -void FrameCaret::setCaretRectNeedsUpdate() { - if (m_caretRectDirty) - return; - m_caretRectDirty = true; +void FrameCaret::clearPreviousVisualRect(const LayoutBlock& block) { + m_caretBase->clearPreviousVisualRect(block); +} - if (Page* page = m_frame->page()) - page->animator().scheduleVisualUpdate(m_frame->localFrameRoot()); +void FrameCaret::layoutBlockWillBeDestroyed(const LayoutBlock& block) { + m_caretBase->layoutBlockWillBeDestroyed(block); +} - // Ensure the frame will be checked for paint invalidation during - // PrePaintTreeWalk. - if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled()) { - if (auto layoutItem = m_frame->ownerLayoutItem()) - layoutItem.setMayNeedPaintInvalidation(); - } +void FrameCaret::updateStyleAndLayoutIfNeeded() { + bool shouldPaintCaret = + m_shouldPaintCaret && isActive() && + m_caretVisibility == CaretVisibility::Visible && + m_selectionEditor->visibleSelection<EditingStrategy>().hasEditableStyle(); + + m_caretBase->updateStyleAndLayoutIfNeeded( + shouldPaintCaret ? caretPosition() : PositionWithAffinity()); +} + +void FrameCaret::invalidatePaintIfNeeded(const LayoutBlock& block, + const PaintInvalidatorContext& context, + PaintInvalidationReason reason) { + m_caretBase->invalidatePaintIfNeeded(block, context, reason); } bool FrameCaret::caretPositionIsValidForDocument( @@ -172,70 +171,12 @@ return caretPosition().document() == document && !caretPosition().isOrphan(); } -static bool shouldRepaintCaret(Node& node) { - // If PositionAnchorType::BeforeAnchor or PositionAnchorType::AfterAnchor, - // carets need to be repainted not only when the node is contentEditable but - // also when its parentNode() is contentEditable. - node.document().updateStyleAndLayoutTree(); - return hasEditableStyle(node) || - (node.parentNode() && hasEditableStyle(*node.parentNode())); -} - -void FrameCaret::invalidateCaretRect(bool forceInvalidation) { - if (!m_caretRectDirty) - return; - m_caretRectDirty = false; - - DCHECK(caretPositionIsValidForDocument(*m_frame->document())); - LayoutObject* layoutObject = nullptr; - LayoutRect newRect; - PositionWithAffinity currentCaretPosition = caretPosition(); - if (isActive()) - newRect = localCaretRectOfPosition(currentCaretPosition, layoutObject); - Node* newNode = layoutObject ? layoutObject->node() : nullptr; - // The current selected node |newNode| could be a child multiple levels below - // its associated "anchor node" ancestor, so we reference and keep around the - // anchor node for checking editability. - // TODO(wkorman): Consider storing previous Position, rather than Node, and - // making use of EditingUtilies::isEditablePosition() directly. - Node* newAnchorNode = - currentCaretPosition.position().parentAnchoredEquivalent().anchorNode(); - if (newNode && newAnchorNode && newNode != newAnchorNode && - newAnchorNode->layoutObject() && newAnchorNode->layoutObject()->isBox()) { - newNode->layoutObject()->mapToVisualRectInAncestorSpace( - toLayoutBoxModelObject(newAnchorNode->layoutObject()), newRect); - } - // It's possible for the timer to be inactive even though we want to - // invalidate the caret. For example, when running as a layout test the - // caret blink interval could be zero and thus |m_caretBlinkTimer| will - // never be started. We provide |forceInvalidation| for use by paint - // invalidation internals where we need to invalidate the caret regardless - // of timer state. - if (!forceInvalidation && !m_caretBlinkTimer.isActive() && - newNode == m_previousCaretNode && newRect == m_previousCaretRect && - m_caretVisibility == m_previousCaretVisibility) - return; - - if (m_previousCaretAnchorNode && - shouldRepaintCaret(*m_previousCaretAnchorNode)) { - m_caretBase->invalidateLocalCaretRect(m_previousCaretAnchorNode.get(), - m_previousCaretRect); - } - if (newAnchorNode && shouldRepaintCaret(*newAnchorNode)) - m_caretBase->invalidateLocalCaretRect(newAnchorNode, newRect); - m_previousCaretNode = newNode; - m_previousCaretAnchorNode = newAnchorNode; - m_previousCaretRect = newRect; - m_previousCaretVisibility = m_caretVisibility; -} - static IntRect absoluteBoundsForLocalRect(Node* node, const LayoutRect& rect) { - LayoutBlock* caretPainter = CaretDisplayItemClient::caretLayoutObject(node); + LayoutBlock* caretPainter = CaretDisplayItemClient::caretLayoutBlock(node); if (!caretPainter) return IntRect(); LayoutRect localRect(rect); - caretPainter->flipForWritingMode(localRect); return caretPainter->localToAbsoluteQuad(FloatRect(localRect)) .enclosingBoundingBox(); } @@ -250,13 +191,6 @@ Node* const caretNode = caretPosition().anchorNode(); if (!isActive()) return absoluteBoundsForLocalRect(caretNode, LayoutRect()); - // TODO(yosin): We should get rid of text control short path since layout - // tree is clean. - if (enclosingTextControl(caretPosition().position()) && - isVisuallyEquivalentCandidate(caretPosition().position())) { - return absoluteBoundsForLocalRect( - caretNode, CaretDisplayItemClient::computeCaretRect(caretPosition())); - } return absoluteBoundsForLocalRect( caretNode, CaretDisplayItemClient::computeCaretRect( @@ -271,46 +205,13 @@ updateAppearance(); } +bool FrameCaret::shouldPaintCaret(const LayoutBlock& block) const { + return m_caretBase->shouldPaintCaret(block); +} + void FrameCaret::paintCaret(GraphicsContext& context, - const LayoutPoint& paintOffset) { - if (m_caretVisibility == CaretVisibility::Hidden) - return; - - if (!(isActive() && m_shouldPaintCaret)) - return; - - const LayoutRect caretLocalRect = - CaretDisplayItemClient::computeCaretRect(caretPosition()); - m_caretBase->paintCaret(caretPosition().anchorNode(), context, caretLocalRect, - paintOffset, DisplayItem::kCaret); -} - -void FrameCaret::dataWillChange(const CharacterData& node) { - if (node == m_previousCaretNode) { - // This invalidation is eager, and intentionally uses stale state. - DisableCompositingQueryAsserts disabler; - m_caretBase->invalidateLocalCaretRect(m_previousCaretAnchorNode.get(), - m_previousCaretRect); - } -} - -void FrameCaret::nodeWillBeRemoved(Node& node) { - if (node != m_previousCaretNode && node != m_previousCaretAnchorNode) - return; - // Hits in ManualTests/caret-paint-after-last-text-is-removed.html - DisableCompositingQueryAsserts disabler; - m_caretBase->invalidateLocalCaretRect(m_previousCaretAnchorNode.get(), - m_previousCaretRect); - m_previousCaretNode = nullptr; - m_previousCaretAnchorNode = nullptr; - m_previousCaretRect = LayoutRect(); - m_previousCaretVisibility = CaretVisibility::Hidden; -} - -void FrameCaret::contextDestroyed(Document*) { - m_caretBlinkTimer.stop(); - m_previousCaretNode.clear(); - m_previousCaretAnchorNode.clear(); + const LayoutPoint& paintOffset) const { + m_caretBase->paintCaret(context, paintOffset, DisplayItem::kCaret); } bool FrameCaret::shouldBlinkCaret() const { @@ -334,7 +235,12 @@ if (isCaretBlinkingSuspended() && m_shouldPaintCaret) return; m_shouldPaintCaret = !m_shouldPaintCaret; - setCaretRectNeedsUpdate(); + scheduleVisualUpdateForPaintInvalidationIfNeeded(); +} + +void FrameCaret::scheduleVisualUpdateForPaintInvalidationIfNeeded() { + if (FrameView* frameView = m_frame->view()) + frameView->scheduleVisualUpdateForPaintInvalidationIfNeeded(); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/FrameCaret.h b/third_party/WebKit/Source/core/editing/FrameCaret.h index cbe7ead..b546a80 100644 --- a/third_party/WebKit/Source/core/editing/FrameCaret.h +++ b/third_party/WebKit/Source/core/editing/FrameCaret.h
@@ -26,33 +26,31 @@ #ifndef FrameCaret_h #define FrameCaret_h +#include <memory> #include "core/CoreExport.h" -#include "core/dom/SynchronousMutationObserver.h" #include "core/editing/PositionWithAffinity.h" #include "platform/Timer.h" #include "platform/geometry/LayoutRect.h" +#include "platform/graphics/PaintInvalidationReason.h" #include "platform/heap/GarbageCollected.h" #include "platform/heap/Member.h" -#include <memory> namespace blink { class CaretDisplayItemClient; -class CharacterData; class DisplayItemClient; class Document; +class FrameCaret; class GraphicsContext; -class Node; +class LayoutBlock; class LocalFrame; class SelectionEditor; +struct PaintInvalidatorContext; enum class CaretVisibility { Visible, Hidden }; class CORE_EXPORT FrameCaret final - : public GarbageCollectedFinalized<FrameCaret>, - public SynchronousMutationObserver { - USING_GARBAGE_COLLECTED_MIXIN(FrameCaret); - + : public GarbageCollectedFinalized<FrameCaret> { public: FrameCaret(LocalFrame&, const SelectionEditor&); ~FrameCaret(); @@ -60,7 +58,6 @@ const DisplayItemClient& displayItemClient() const; bool isActive() const { return caretPosition().isNotNull(); } - void documentAttached(Document*); void updateAppearance(); // Used to suspend caret blinking while the mouse is down. @@ -70,24 +67,27 @@ bool isCaretBlinkingSuspended() const { return m_isCaretBlinkingSuspended; } void stopCaretBlinkTimer(); void startBlinkCaret(); - void setCaretVisibility(CaretVisibility); - void setCaretRectNeedsUpdate(); - // If |forceInvalidation| is true the caret's previous and new rectangles - // are forcibly invalidated regardless of the state of the blink timer. - void invalidateCaretRect(bool forceInvalidation); IntRect absoluteCaretBounds() const; bool shouldShowBlockCursor() const { return m_shouldShowBlockCursor; } void setShouldShowBlockCursor(bool); - void paintCaret(GraphicsContext&, const LayoutPoint&); + // Paint invalidation methods delegating to DisplayItemClient. + void clearPreviousVisualRect(const LayoutBlock&); + void layoutBlockWillBeDestroyed(const LayoutBlock&); + void updateStyleAndLayoutIfNeeded(); + void invalidatePaintIfNeeded(const LayoutBlock&, + const PaintInvalidatorContext&, + PaintInvalidationReason); - void dataWillChange(const CharacterData&); + bool shouldPaintCaret(const LayoutBlock&) const; + void paintCaret(GraphicsContext&, const LayoutPoint&) const; - // For unittests + // For unit tests. + const DisplayItemClient& caretDisplayItemClientForTesting() const; + const LayoutBlock* caretLayoutBlockForTesting() const; bool shouldPaintCaretForTesting() const { return m_shouldPaintCaret; } - bool isPreviousCaretDirtyForTesting() const { return m_previousCaretNode; } DECLARE_TRACE(); @@ -100,23 +100,14 @@ void caretBlinkTimerFired(TimerBase*); bool caretPositionIsValidForDocument(const Document&) const; - // Implementation of |SynchronousMutationObserver| member functions. - void contextDestroyed(Document*) final; - void nodeWillBeRemoved(Node&) final; + void scheduleVisualUpdateForPaintInvalidationIfNeeded(); const Member<const SelectionEditor> m_selectionEditor; const Member<LocalFrame> m_frame; const std::unique_ptr<CaretDisplayItemClient> m_caretBase; - // The last node which painted the caret. Retained for clearing the old - // caret when it moves. - Member<Node> m_previousCaretNode; - Member<Node> m_previousCaretAnchorNode; - LayoutRect m_previousCaretRect; CaretVisibility m_caretVisibility; - CaretVisibility m_previousCaretVisibility; // TODO(https://crbug.com/668758): Consider using BeginFrame update for this. TaskRunnerTimer<FrameCaret> m_caretBlinkTimer; - bool m_caretRectDirty : 1; bool m_shouldPaintCaret : 1; bool m_isCaretBlinkingSuspended : 1; bool m_shouldShowBlockCursor : 1;
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.cpp b/third_party/WebKit/Source/core/editing/FrameSelection.cpp index f7678ec..910761e 100644 --- a/third_party/WebKit/Source/core/editing/FrameSelection.cpp +++ b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
@@ -168,15 +168,16 @@ visiblePositionForContentsPoint(point, frame()); SelectionInDOMTree::Builder builder; builder.setIsDirectional(selection().isDirectional()); + builder.setIsHandleVisible(true); if (position.isNotNull()) builder.collapse(position.toPositionWithAffinity()); - setSelection(builder.build(), - CloseTyping | ClearTypingStyle | UserTriggered | HandleVisible); + setSelection(builder.build(), CloseTyping | ClearTypingStyle | UserTriggered); } template <typename Strategy> void FrameSelection::setSelectionAlgorithm( const VisibleSelectionTemplate<Strategy>& newSelection, + HandleVisibility handleVisibility, SetSelectionOptions options, CursorAlignOnScroll align, TextGranularity granularity) { @@ -188,9 +189,6 @@ m_granularityStrategy->Clear(); bool closeTyping = options & CloseTyping; bool shouldClearTypingStyle = options & ClearTypingStyle; - const HandleVisibility handleVisibility = options & HandleVisible - ? HandleVisibility::Visible - : HandleVisibility::NotVisible; EUserTriggered userTriggered = selectionOptionsToUserTriggered(options); // TODO(editing-dev): We should rename variable |s| to another name to avoid @@ -213,7 +211,6 @@ m_handleVisibility == handleVisibility) { // Even if selection was not changed, selection offsets may have been // changed. - m_frame->inputMethodController().cancelCompositionIfSelectionIsInvalid(); notifyLayoutObjectOfSelectionChange(userTriggered); return; } @@ -224,7 +221,7 @@ m_handleVisibility = handleVisibility; m_selectionEditor->setVisibleSelection(s, options); - m_frameCaret->setCaretRectNeedsUpdate(); + scheduleVisualUpdateForPaintInvalidationIfNeeded(); if (!s.isNone() && !(options & DoNotSetFocus)) { setFocusedNodeIfNeeded(); @@ -239,9 +236,6 @@ } if (!(options & DoNotUpdateAppearance)) { - // Hits in - // compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents.html - DisableCompositingQueryAsserts disabler; m_frameCaret->stopCaretBlinkTimer(); updateAppearance(); } @@ -263,10 +257,9 @@ // boundary, selection for the DOM tree is shrunk while that for the // flat tree is not. Additionally, this case occurs in some edge cases. // See also: editing/pasteboard/4076267-3.html - if (oldSelection == m_selectionEditor->visibleSelection<Strategy>()) { - m_frame->inputMethodController().cancelCompositionIfSelectionIsInvalid(); + if (oldSelection == m_selectionEditor->visibleSelection<Strategy>()) return; - } + m_frame->editor().respondToChangedSelection(oldSelectionStart, options); if (userTriggered == UserTriggered) { ScrollAlignment alignment; @@ -304,8 +297,10 @@ .document() ->updateStyleAndLayoutIgnorePendingStylesheets(); } - setSelection(createVisibleSelection(newSelection), options, align, - granularity); + setSelection(createVisibleSelection(newSelection), + newSelection.isHandleVisible() ? HandleVisibility::Visible + : HandleVisibility::NotVisible, + options, align, granularity); } // TODO(yosin): We will make |selectionInFlatTree| version of |SetSelection()| @@ -322,25 +317,40 @@ .document() ->updateStyleAndLayoutIgnorePendingStylesheets(); } - setSelection(createVisibleSelection(newSelection), options, align, - granularity); + setSelection(createVisibleSelection(newSelection), + newSelection.isHandleVisible() ? HandleVisibility::Visible + : HandleVisibility::NotVisible, + options, align, granularity); } void FrameSelection::setSelection(const VisibleSelection& newSelection, + HandleVisibility handleVisibility, SetSelectionOptions options, CursorAlignOnScroll align, TextGranularity granularity) { - setSelectionAlgorithm<EditingStrategy>(newSelection, options, align, - granularity); + setSelectionAlgorithm<EditingStrategy>(newSelection, handleVisibility, + options, align, granularity); +} + +void FrameSelection::setSelection(const VisibleSelection& newSelection, + SetSelectionOptions options) { + setSelection(newSelection, HandleVisibility::NotVisible, options); } void FrameSelection::setSelection( const VisibleSelectionInFlatTree& newSelection, + HandleVisibility handleVisibility, SetSelectionOptions options, CursorAlignOnScroll align, TextGranularity granularity) { - setSelectionAlgorithm<EditingInFlatTreeStrategy>(newSelection, options, align, - granularity); + setSelectionAlgorithm<EditingInFlatTreeStrategy>( + newSelection, handleVisibility, options, align, granularity); +} + +void FrameSelection::setSelection( + const VisibleSelectionInFlatTree& newSelection, + SetSelectionOptions options) { + setSelection(newSelection, HandleVisibility::NotVisible, options); } static bool removingNodeRemovesPosition(Node& node, const Position& position) { @@ -386,7 +396,6 @@ m_selectionEditor->setWithoutValidation(newStart, newEnd); else m_selectionEditor->setWithoutValidation(newEnd, newStart); - m_frameCaret->setCaretRectNeedsUpdate(); if (document().isRunningExecCommand()) return; TypingCommand::closeTyping(m_frame); @@ -466,7 +475,6 @@ if (clearDOMTreeSelection) setSelection(SelectionInDOMTree(), DoNotSetFocus); - m_frameCaret->setCaretRectNeedsUpdate(); // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to // |Editor| class. @@ -677,7 +685,7 @@ if (userTriggered == UserTriggered) m_granularity = CharacterGranularity; - m_frameCaret->setCaretRectNeedsUpdate(); + scheduleVisualUpdateForPaintInvalidationIfNeeded(); return true; } @@ -691,7 +699,7 @@ return false; } - setSelection(selectionModifier.selection(), + setSelection(selectionModifier.selection(), HandleVisibility::NotVisible, CloseTyping | ClearTypingStyle | UserTriggered, alter == AlterationMove ? CursorAlignOnScroll::Always : CursorAlignOnScroll::IfNeeded); @@ -712,7 +720,6 @@ DCHECK(document); m_useSecureKeyboardEntryWhenActive = false; m_selectionEditor->documentAttached(document); - m_frameCaret->documentAttached(document); setContext(document); } @@ -727,13 +734,31 @@ m_selectionEditor->documentDetached(*document); } -bool FrameSelection::hasCaretIn(const LayoutBlock& layoubBlock) const { +void FrameSelection::clearPreviousCaretVisualRect(const LayoutBlock& block) { + m_frameCaret->clearPreviousVisualRect(block); +} + +void FrameSelection::layoutBlockWillBeDestroyed(const LayoutBlock& block) { + m_frameCaret->layoutBlockWillBeDestroyed(block); +} + +void FrameSelection::updateStyleAndLayoutIfNeeded() { + m_frameCaret->updateStyleAndLayoutIfNeeded(); +} + +void FrameSelection::invalidatePaintIfNeeded( + const LayoutBlock& block, + const PaintInvalidatorContext& context, + PaintInvalidationReason reason) { + m_frameCaret->invalidatePaintIfNeeded(block, context, reason); +} + +bool FrameSelection::shouldPaintCaret(const LayoutBlock& block) const { DCHECK(selection().isValidFor(document())); - if (!isCaret()) - return false; - return CaretDisplayItemClient::caretLayoutObject( - selection().start().anchorNode()) == layoubBlock && - hasEditableStyle(); + + bool result = m_frameCaret->shouldPaintCaret(block); + DCHECK(!result || (isCaret() && hasEditableStyle())); + return result; } IntRect FrameSelection::absoluteCaretBounds() { @@ -741,14 +766,6 @@ return m_frameCaret->absoluteCaretBounds(); } -void FrameSelection::invalidateCaretRect(bool forceInvalidation) { - m_frameCaret->invalidateCaretRect(forceInvalidation); -} - -void FrameSelection::dataWillChange(const CharacterData& node) { - m_frameCaret->dataWillChange(node); -} - void FrameSelection::paintCaret(GraphicsContext& context, const LayoutPoint& paintOffset) { m_frameCaret->paintCaret(context, paintOffset); @@ -915,7 +932,10 @@ return; } - setSelection(SelectionInDOMTree::Builder().selectAllChildren(*root).build()); + setSelection(SelectionInDOMTree::Builder() + .selectAllChildren(*root) + .setIsHandleVisible(isHandleVisible()) + .build()); selectFrameElementInParentIfFullySelected(); notifyLayoutObjectOfSelectionChange(UserTriggered); } @@ -1051,7 +1071,6 @@ } void FrameSelection::didLayout() { - setCaretRectNeedsUpdate(); updateAppearance(); } @@ -1311,6 +1330,11 @@ page->animator().scheduleVisualUpdate(m_frame->localFrameRoot()); } +void FrameSelection::scheduleVisualUpdateForPaintInvalidationIfNeeded() const { + if (FrameView* frameView = m_frame->view()) + frameView->scheduleVisualUpdateForPaintInvalidationIfNeeded(); +} + bool FrameSelection::selectWordAroundPosition(const VisiblePosition& position) { static const EWordSide wordSideList[2] = {RightWordIfOnBoundary, LeftWordIfOnBoundary}; @@ -1359,10 +1383,9 @@ VisibleSelection newSelection = granularityStrategy()->updateExtent(contentsPoint, m_frame); - setSelection(newSelection, + setSelection(newSelection, HandleVisibility::Visible, FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle | - FrameSelection::DoNotClearStrategy | UserTriggered | - FrameSelection::HandleVisible, + FrameSelection::DoNotClearStrategy | UserTriggered, CursorAlignOnScroll::IfNeeded, CharacterGranularity); } @@ -1383,11 +1406,8 @@ if (newSelection.isNone()) return; - SetSelectionOptions options = CloseTyping | ClearTypingStyle; - if (isHandleVisible()) - options |= HandleVisible; - setSelection(newSelection, options, CursorAlignOnScroll::IfNeeded, - granularity); + setSelection(newSelection, m_handleVisibility, CloseTyping | ClearTypingStyle, + CursorAlignOnScroll::IfNeeded, granularity); } void FrameSelection::updateIfNeeded() { @@ -1400,18 +1420,6 @@ : CaretVisibility::Hidden); } -bool FrameSelection::shouldPaintCaretForTesting() const { - return m_frameCaret->shouldPaintCaretForTesting(); -} - -bool FrameSelection::isPreviousCaretDirtyForTesting() const { - return m_frameCaret->isPreviousCaretDirtyForTesting(); -} - -void FrameSelection::setCaretRectNeedsUpdate() { - m_frameCaret->setCaretRectNeedsUpdate(); -} - void FrameSelection::setCaretBlinkingSuspended(bool suspended) { m_frameCaret->setCaretBlinkingSuspended(suspended); }
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.h b/third_party/WebKit/Source/core/editing/FrameSelection.h index 0ff79f1..5276dd66 100644 --- a/third_party/WebKit/Source/core/editing/FrameSelection.h +++ b/third_party/WebKit/Source/core/editing/FrameSelection.h
@@ -27,6 +27,7 @@ #ifndef FrameSelection_h #define FrameSelection_h +#include <memory> #include "core/CoreExport.h" #include "core/dom/Range.h" #include "core/dom/SynchronousMutationObserver.h" @@ -38,9 +39,9 @@ #include "platform/Timer.h" #include "platform/geometry/IntRect.h" #include "platform/geometry/LayoutRect.h" +#include "platform/graphics/PaintInvalidationReason.h" #include "platform/heap/Handle.h" #include "wtf/Noncopyable.h" -#include <memory> namespace blink { @@ -56,6 +57,7 @@ class PendingSelection; class Text; class TextIteratorBehavior; +struct PaintInvalidatorContext; enum class CursorAlignOnScroll { IfNeeded, Always }; @@ -90,7 +92,6 @@ DoNotUpdateAppearance = 1 << 4, DoNotClearStrategy = 1 << 5, DoNotAdjustInFlatTree = 1 << 6, - HandleVisible = 1 << 7, }; // Union of values in SetSelectionOption and EUserTriggered typedef unsigned SetSelectionOptions; @@ -137,15 +138,19 @@ // TODO(yosin): We should use |SelectionInDOMTree| version instead of // |VisibleSelection| version. void setSelection(const VisibleSelection&, + HandleVisibility = HandleVisibility::NotVisible, SetSelectionOptions = CloseTyping | ClearTypingStyle, CursorAlignOnScroll = CursorAlignOnScroll::IfNeeded, TextGranularity = CharacterGranularity); + void setSelection(const VisibleSelection&, SetSelectionOptions); // TODO(yosin): We should use |SelectionInFlatTree| version instead of // |VisibleSelectionInFlatTree| version. void setSelection(const VisibleSelectionInFlatTree&, + HandleVisibility = HandleVisibility::NotVisible, SetSelectionOptions = CloseTyping | ClearTypingStyle, CursorAlignOnScroll = CursorAlignOnScroll::IfNeeded, TextGranularity = CharacterGranularity); + void setSelection(const VisibleSelectionInFlatTree&, SetSelectionOptions); bool setSelectedRange( const EphemeralRange&, TextAffinity, @@ -189,9 +194,9 @@ Position start() const { return selection().start(); } Position end() const { return selection().end(); } - // Returns true if specified layout block has caret. This function is - // called during InRecalStyle and InPaint. - bool hasCaretIn(const LayoutBlock&) const; + // Returns true if specified layout block should paint caret. This function is + // called during painting only. + bool shouldPaintCaret(const LayoutBlock&) const; // Bounds of (possibly transformed) caret in absolute coords IntRect absoluteCaretBounds(); @@ -210,15 +215,22 @@ Range* firstRange() const; void documentAttached(Document*); - void dataWillChange(const CharacterData& node); void didLayout(); bool isAppearanceDirty() const; void commitAppearanceIfNeeded(LayoutView&); void setCaretVisible(bool caretIsVisible); - void setCaretRectNeedsUpdate(); void scheduleVisualUpdate() const; - void invalidateCaretRect(bool forceInvalidation = false); + void scheduleVisualUpdateForPaintInvalidationIfNeeded() const; + + // Paint invalidation methods delegating to FrameCaret. + void clearPreviousCaretVisualRect(const LayoutBlock&); + void layoutBlockWillBeDestroyed(const LayoutBlock&); + void updateStyleAndLayoutIfNeeded(); + void invalidatePaintIfNeeded(const LayoutBlock&, + const PaintInvalidatorContext&, + PaintInvalidationReason); + void paintCaret(GraphicsContext&, const LayoutPoint&); // Used to suspend caret blinking while the mouse is down. @@ -280,6 +292,7 @@ DECLARE_TRACE(); private: + friend class BlockPaintInvalidatorTest; friend class FrameSelectionTest; friend class PaintControllerPaintTestForSlimmingPaintV1AndV2; friend class SelectionControllerTest; @@ -288,7 +301,6 @@ explicit FrameSelection(LocalFrame&); - // For |PaintControllerPaintTestForSlimmingPaintV1AndV2|. const DisplayItemClient& caretDisplayItemClientForTesting() const; // Note: We have |selectionInFlatTree()| for unit tests, we should @@ -297,6 +309,7 @@ template <typename Strategy> void setSelectionAlgorithm(const VisibleSelectionTemplate<Strategy>&, + HandleVisibility, SetSelectionOptions, CursorAlignOnScroll, TextGranularity); @@ -335,10 +348,6 @@ unsigned oldLength) final; void didSplitTextNode(const Text& oldNode) final; - // For unittests - bool shouldPaintCaretForTesting() const; - bool isPreviousCaretDirtyForTesting() const; - Member<LocalFrame> m_frame; const Member<PendingSelection> m_pendingSelection; const Member<SelectionEditor> m_selectionEditor;
diff --git a/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp b/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp index 96c14d1..e5e13b0e 100644 --- a/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp +++ b/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp
@@ -4,6 +4,7 @@ #include "core/editing/FrameSelection.h" +#include <memory> #include "bindings/core/v8/ExceptionState.h" #include "core/dom/Document.h" #include "core/dom/Element.h" @@ -14,6 +15,7 @@ #include "core/frame/FrameView.h" #include "core/html/HTMLBodyElement.h" #include "core/input/EventHandler.h" +#include "core/layout/LayoutBlock.h" #include "core/paint/PaintInfo.h" #include "core/paint/PaintLayer.h" #include "core/testing/DummyPageHolder.h" @@ -23,7 +25,6 @@ #include "wtf/PassRefPtr.h" #include "wtf/RefPtr.h" #include "wtf/StdLibExtras.h" -#include <memory> namespace blink { @@ -41,17 +42,6 @@ return dummyPageHolder().frameView().layoutCount(); } - bool isCaretBoundsDirty() const { - return selection().m_frameCaret->m_caretRectDirty; - } - - bool shouldPaintCaretForTesting() const { - return selection().shouldPaintCaretForTesting(); - } - bool isPreviousCaretDirtyForTesting() const { - return selection().isPreviousCaretDirtyForTesting(); - } - PositionWithAffinity caretPosition() const { return selection().m_frameCaret->caretPosition(); } @@ -76,25 +66,6 @@ EXPECT_FALSE(selection().isNone()); } -TEST_F(FrameSelectionTest, InvalidateCaretRect) { - Text* text = appendTextNode("Hello, World!"); - document().view()->updateAllLifecyclePhases(); - - selection().setSelection( - SelectionInDOMTree::Builder().collapse(Position(text, 0)).build()); - selection().setCaretRectNeedsUpdate(); - EXPECT_TRUE(isCaretBoundsDirty()); - selection().invalidateCaretRect(); - EXPECT_FALSE(isCaretBoundsDirty()); - - document().body()->removeChild(text); - document().updateStyleAndLayoutIgnorePendingStylesheets(); - selection().setCaretRectNeedsUpdate(); - EXPECT_TRUE(isCaretBoundsDirty()); - selection().invalidateCaretRect(); - EXPECT_FALSE(isCaretBoundsDirty()); -} - TEST_F(FrameSelectionTest, PaintCaretShouldNotLayout) { Text* text = appendTextNode("Hello, World!"); document().view()->updateAllLifecyclePhases(); @@ -106,8 +77,10 @@ selection().setCaretVisible(true); selection().setSelection( SelectionInDOMTree::Builder().collapse(Position(text, 0)).build()); + document().view()->updateAllLifecyclePhases(); EXPECT_TRUE(selection().isCaret()); - EXPECT_TRUE(shouldPaintCaretForTesting()); + EXPECT_TRUE(toLayoutBlock(document().body()->layoutObject()) + ->shouldPaintCursorCaret()); int startCount = layoutCount(); { @@ -127,58 +100,6 @@ EXPECT_EQ(startCount, layoutCount()); } -TEST_F(FrameSelectionTest, InvalidatePreviousCaretAfterRemovingLastCharacter) { - Text* text = appendTextNode("Hello, World!"); - document().view()->updateAllLifecyclePhases(); - - document().body()->setContentEditable("true", ASSERT_NO_EXCEPTION); - document().body()->focus(); - EXPECT_TRUE(document().body()->isFocused()); - - selection().setCaretVisible(true); - EXPECT_TRUE(selection().isCaret()); - EXPECT_TRUE(shouldPaintCaretForTesting()); - - // Simulate to type "Hello, World!". - DisableCompositingQueryAsserts disabler; - document().updateStyleAndLayout(); - selection().setSelection( - SelectionInDOMTree::Builder().collapse(selection().end()).build()); - selection().setCaretRectNeedsUpdate(); - EXPECT_TRUE(isCaretBoundsDirty()); - EXPECT_FALSE(isPreviousCaretDirtyForTesting()); - selection().invalidateCaretRect(); - EXPECT_FALSE(isCaretBoundsDirty()); - EXPECT_TRUE(isPreviousCaretDirtyForTesting()); - - // Simulate to remove all except for "H". - text->replaceWholeText("H"); - document().updateStyleAndLayout(); - selection().setSelection( - SelectionInDOMTree::Builder().collapse(selection().end()).build()); - selection().setCaretRectNeedsUpdate(); - EXPECT_TRUE(isCaretBoundsDirty()); - // "H" remains so early previousCaret invalidation isn't needed. - EXPECT_TRUE(isPreviousCaretDirtyForTesting()); - selection().invalidateCaretRect(); - EXPECT_FALSE(isCaretBoundsDirty()); - EXPECT_TRUE(isPreviousCaretDirtyForTesting()); - - // Simulate to remove the last character. - document().body()->removeChild(text); - // This line is the objective of this test. - // As removing the last character, early previousCaret invalidation is - // executed. - EXPECT_FALSE(isPreviousCaretDirtyForTesting()); - document().updateStyleAndLayoutIgnorePendingStylesheets(); - selection().setCaretRectNeedsUpdate(); - EXPECT_TRUE(isCaretBoundsDirty()); - EXPECT_FALSE(isPreviousCaretDirtyForTesting()); - selection().invalidateCaretRect(); - EXPECT_FALSE(isCaretBoundsDirty()); - EXPECT_TRUE(isPreviousCaretDirtyForTesting()); -} - #define EXPECT_EQ_SELECTED_TEXT(text) \ EXPECT_EQ(text, WebString(selection().selectedText()).utf8()) @@ -308,6 +229,33 @@ "selctable."; } +TEST_F(FrameSelectionTest, SelectAllPreservesHandle) { + setBodyContent("<div id=sample>abc</div>"); + Element* sample = document().getElementById("sample"); + const Position endOfText(sample->firstChild(), 3); + selection().setSelection(SelectionInDOMTree::Builder() + .collapse(endOfText) + .setIsHandleVisible(false) + .build()); + EXPECT_FALSE(selection().isHandleVisible()); + selection().selectAll(); + EXPECT_FALSE(selection().isHandleVisible()) + << "If handles weren't present before" + "selectAll. Then they shouldn't be present" + "after it."; + + selection().setSelection(SelectionInDOMTree::Builder() + .collapse(endOfText) + .setIsHandleVisible(true) + .build()); + EXPECT_TRUE(selection().isHandleVisible()); + selection().selectAll(); + EXPECT_TRUE(selection().isHandleVisible()) + << "If handles were present before" + "selectAll. Then they should be present" + "after it."; +} + TEST_F(FrameSelectionTest, updateIfNeededAndFrameCaret) { setBodyContent("<style id=sample></style>"); document().setDesignMode("on");
diff --git a/third_party/WebKit/Source/core/editing/InputMethodController.cpp b/third_party/WebKit/Source/core/editing/InputMethodController.cpp index e1443826..538a611 100644 --- a/third_party/WebKit/Source/core/editing/InputMethodController.cpp +++ b/third_party/WebKit/Source/core/editing/InputMethodController.cpp
@@ -267,7 +267,11 @@ const String& composing = composingText(); if (confirmBehavior == KeepSelection) { - PlainTextRange oldOffsets = getSelectionOffsets(); + // Do not dismiss handles even if we are moving selection, because we will + // eventually move back to the old selection offsets. + const bool isHandleVisible = frame().selection().isHandleVisible(); + + const PlainTextRange& oldOffsets = getSelectionOffsets(); Editor::RevealSelectionScope revealSelectionScope(&editor()); clear(); @@ -276,7 +280,17 @@ // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets // needs to be audited. see http://crbug.com/590369 for more details. document().updateStyleAndLayoutIgnorePendingStylesheets(); - setSelectionOffsets(oldOffsets); + + const EphemeralRange& oldSelectionRange = + ephemeralRangeForOffsets(oldOffsets); + if (oldSelectionRange.isNull()) + return false; + const SelectionInDOMTree& selection = + SelectionInDOMTree::Builder() + .setBaseAndExtent(oldSelectionRange) + .setIsHandleVisible(isHandleVisible) + .build(); + frame().selection().setSelection(selection, FrameSelection::CloseTyping); return true; } @@ -469,22 +483,6 @@ dispatchCompositionEndEvent(frame(), emptyString); } -void InputMethodController::cancelCompositionIfSelectionIsInvalid() { - if (!hasComposition() || editor().preventRevealSelection()) - return; - - // Check if selection start and selection end are valid. - FrameSelection& selection = frame().selection(); - if (!selection.isNone() && !m_compositionRange->collapsed()) { - if (selection.start().compareTo(m_compositionRange->startPosition()) >= 0 && - selection.end().compareTo(m_compositionRange->endPosition()) <= 0) - return; - } - - cancelComposition(); - frame().chromeClient().didCancelCompositionOnSelectionChange(); -} - // If current position is at grapheme boundary, return 0; otherwise, return the // distance to its nearest left grapheme boundary. static size_t computeDistanceToLeftGraphemeBoundary(const Position& position) { @@ -713,19 +711,23 @@ return PlainTextRange::create(*editable, range); } -bool InputMethodController::setSelectionOffsets( - const PlainTextRange& selectionOffsets, - FrameSelection::SetSelectionOptions options) { - if (selectionOffsets.isNull()) - return false; +EphemeralRange InputMethodController::ephemeralRangeForOffsets( + const PlainTextRange& offsets) const { + if (offsets.isNull()) + return EphemeralRange(); Element* rootEditableElement = frame().selection().rootEditableElement(); if (!rootEditableElement) - return false; + return EphemeralRange(); DCHECK(!document().needsLayoutTreeUpdate()); - const EphemeralRange range = - selectionOffsets.createRange(*rootEditableElement); + return offsets.createRange(*rootEditableElement); +} + +bool InputMethodController::setSelectionOffsets( + const PlainTextRange& selectionOffsets, + FrameSelection::SetSelectionOptions options) { + const EphemeralRange range = ephemeralRangeForOffsets(selectionOffsets); if (range.isNull()) return false;
diff --git a/third_party/WebKit/Source/core/editing/InputMethodController.h b/third_party/WebKit/Source/core/editing/InputMethodController.h index e757a6a3..09a2152 100644 --- a/third_party/WebKit/Source/core/editing/InputMethodController.h +++ b/third_party/WebKit/Source/core/editing/InputMethodController.h
@@ -85,7 +85,6 @@ // Deletes the existing composition text. void cancelComposition(); - void cancelCompositionIfSelectionIsInvalid(); EphemeralRange compositionEphemeralRange() const; Range* compositionRange() const; @@ -126,6 +125,10 @@ String composingText() const; void selectComposition() const; + + EphemeralRange ephemeralRangeForOffsets(const PlainTextRange&) const; + + // Returns true if selection offsets were successfully set. bool setSelectionOffsets( const PlainTextRange&, FrameSelection::SetSelectionOptions = FrameSelection::CloseTyping);
diff --git a/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp b/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp index 212b16c..d89e9b1 100644 --- a/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp +++ b/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp
@@ -309,6 +309,29 @@ EXPECT_STREQ("abc1<b>2</b>37<b>8</b>9", div->innerHTML().utf8().data()); } +TEST_F(InputMethodControllerTest, InsertTextWithNewLine) { + Element* div = + insertHTMLElement("<div id='sample' contenteditable></div>", "sample"); + Vector<CompositionUnderline> underlines; + underlines.push_back(CompositionUnderline(0, 11, Color(255, 0, 0), false, 0)); + + controller().commitText(String("hello\nworld"), underlines, 0); + EXPECT_STREQ("hello<div>world</div>", div->innerHTML().utf8().data()); +} + +TEST_F(InputMethodControllerTest, InsertTextWithNewLineIncrementally) { + Element* div = + insertHTMLElement("<div id='sample' contenteditable></div>", "sample"); + + Vector<CompositionUnderline> underlines; + underlines.push_back(CompositionUnderline(0, 11, Color(255, 0, 0), false, 0)); + controller().setComposition("foo", underlines, 0, 2); + EXPECT_STREQ("foo", div->innerHTML().utf8().data()); + + controller().commitText(String("hello\nworld"), underlines, 0); + EXPECT_STREQ("hello<div>world</div>", div->innerHTML().utf8().data()); +} + TEST_F(InputMethodControllerTest, SelectionOnConfirmExistingText) { insertHTMLElement("<div id='sample' contenteditable>hello world</div>", "sample");
diff --git a/third_party/WebKit/Source/core/editing/SelectionController.cpp b/third_party/WebKit/Source/core/editing/SelectionController.cpp index b798e64..2879cc9 100644 --- a/third_party/WebKit/Source/core/editing/SelectionController.cpp +++ b/third_party/WebKit/Source/core/editing/SelectionController.cpp
@@ -279,12 +279,12 @@ } static SelectionInFlatTree applySelectAll( - const VisibleSelectionInFlatTree& newSelection, + const PositionInFlatTree& basePosition, + const PositionInFlatTree& targetPosition, Node* mousePressNode, const LayoutPoint& dragStartPoint, Node* target, - const LayoutPoint& hitTestPoint, - const VisiblePositionInFlatTree& targetPosition) { + const LayoutPoint& hitTestPoint) { Node* const rootUserSelectAllForMousePressNode = EditingInFlatTreeStrategy::rootUserSelectAllForNode(mousePressNode); Node* const rootUserSelectAllForTarget = @@ -308,7 +308,7 @@ builder.collapse( PositionInFlatTree::afterNode(rootUserSelectAllForMousePressNode)); } else { - builder.collapse(newSelection.base()); + builder.collapse(basePosition); } if (rootUserSelectAllForTarget && mousePressNode->layoutObject()) { @@ -323,7 +323,7 @@ return builder.build(); } - builder.extend(targetPosition.deepEquivalent()); + builder.extend(targetPosition); return builder.build(); } @@ -355,12 +355,14 @@ // Restart the selection if this is the first mouse move. This work is usually // done in handleMousePressEvent, but not if the mouse press was on an // existing selection. - VisibleSelectionInFlatTree newSelection = - selection().visibleSelection<EditingInFlatTreeStrategy>(); // Special case to limit selection to the containing block for SVG text. // FIXME: Isn't there a better non-SVG-specific way to do this? - if (Node* selectionBaseNode = newSelection.base().anchorNode()) { + if (Node* selectionBaseNode = + selection() + .visibleSelection<EditingInFlatTreeStrategy>() + .base() + .anchorNode()) { if (LayoutObject* selectionBaseLayoutObject = selectionBaseNode->layoutObject()) { if (selectionBaseLayoutObject->isSVGText()) { @@ -379,31 +381,26 @@ // |newSelection| are valid for |m_frame->document()|. // |dispatchSelectStart()| can change them by "selectstart" event handler. + PositionInFlatTree basePosition; if (m_selectionState != SelectionState::ExtendedSelection) { // Always extend selection here because it's caused by a mouse drag m_selectionState = SelectionState::ExtendedSelection; - SelectionInFlatTree::Builder builder; - builder.collapse(targetPosition.toPositionWithAffinity()); - newSelection = createVisibleSelection(builder.build()); + basePosition = targetPosition.deepEquivalent(); + } else { + basePosition = + selection().visibleSelection<EditingInFlatTreeStrategy>().base(); } + const SelectionInFlatTree& appliedSelection = applySelectAll( + basePosition, targetPosition.deepEquivalent(), mousePressNode, + dragStartPos, target, hitTestResult.localPoint()); + SelectionInFlatTree::Builder builder(appliedSelection); - newSelection = createVisibleSelection( - applySelectAll(newSelection, mousePressNode, dragStartPos, target, - hitTestResult.localPoint(), targetPosition)); + if (selection().granularity() != CharacterGranularity) + builder.setGranularity(selection().granularity()); - // TODO(yosin): We should have |newBase| and |newExtent| instead of - // |newSelection|. - if (selection().granularity() != CharacterGranularity) { - newSelection = createVisibleSelection( - SelectionInFlatTree::Builder() - .setBaseAndExtent(newSelection.base(), newSelection.extent()) - .setGranularity(selection().granularity()) - .build()); - } - - setNonDirectionalSelectionIfNeeded(newSelection, selection().granularity(), - AdjustEndpointsAtBidiBoundary, - HandleVisibility::NotVisible); + setNonDirectionalSelectionIfNeeded( + createVisibleSelection(builder.build()), selection().granularity(), + AdjustEndpointsAtBidiBoundary, HandleVisibility::NotVisible); } bool SelectionController::updateSelectionForMouseDownDispatchingSelectStart( @@ -691,14 +688,10 @@ selection().isHandleVisible() == isHandleVisible) return; - const FrameSelection::SetSelectionOptions options = - isHandleVisible - ? FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle | - FrameSelection::HandleVisible - : FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle; - - selection().setSelection(newSelection, options, CursorAlignOnScroll::IfNeeded, - granularity); + selection().setSelection( + newSelection, handleVisibility, + FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle, + CursorAlignOnScroll::IfNeeded, granularity); } void SelectionController::setCaretAtHitTestResult( @@ -954,6 +947,8 @@ SelectInputEventType::Touch)) return selection().isAvailable(); + if (!innerNode->isConnected() || !innerNode->layoutObject()) + return false; setCaretAtHitTestResult(hitTestResult); return false; }
diff --git a/third_party/WebKit/Source/core/editing/SelectionControllerTest.cpp b/third_party/WebKit/Source/core/editing/SelectionControllerTest.cpp index 895f76d9..15d8c3e 100644 --- a/third_party/WebKit/Source/core/editing/SelectionControllerTest.cpp +++ b/third_party/WebKit/Source/core/editing/SelectionControllerTest.cpp
@@ -6,6 +6,8 @@ #include "core/editing/EditingTestBase.h" #include "core/editing/FrameSelection.h" +#include "core/frame/FrameView.h" +#include "core/frame/Settings.h" #include "core/input/EventHandler.h" namespace blink { @@ -87,4 +89,20 @@ EXPECT_EQ(PositionInFlatTree(bottom, 3), visibleSelectionInFlatTree().end()); } +TEST_F(SelectionControllerTest, setCaretAtHitTestResult) { + const char* bodyContent = "<div id='sample' contenteditable>sample</div>"; + setBodyContent(bodyContent); + document().settings()->setScriptEnabled(true); + Element* script = document().createElement("script"); + script->setInnerHTML( + "var sample = document.getElementById('sample');" + "sample.addEventListener('onselectstart', " + " event => elem.parentNode.removeChild(elem));"); + document().body()->appendChild(script); + document().view()->updateAllLifecyclePhases(); + frame().eventHandler().selectionController().handleGestureLongPress( + WebGestureEvent(), + frame().eventHandler().hitTestResultAtPoint(IntPoint(8, 8))); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/SelectionModifier.cpp b/third_party/WebKit/Source/core/editing/SelectionModifier.cpp index 81fb057..3e9af85 100644 --- a/third_party/WebKit/Source/core/editing/SelectionModifier.cpp +++ b/third_party/WebKit/Source/core/editing/SelectionModifier.cpp
@@ -869,9 +869,4 @@ return x; } -DEFINE_TRACE(SelectionModifier) { - visitor->trace(m_frame); - visitor->trace(m_selection); -} - } // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/SelectionModifier.h b/third_party/WebKit/Source/core/editing/SelectionModifier.h index ed46226..f9fb61c9 100644 --- a/third_party/WebKit/Source/core/editing/SelectionModifier.h +++ b/third_party/WebKit/Source/core/editing/SelectionModifier.h
@@ -57,8 +57,6 @@ unsigned verticalDistance, VerticalDirection); - DECLARE_VIRTUAL_TRACE(); - private: // TODO(yosin): We should move |EPositionType| to "SelectionModifier.cpp", // it is only used for implementing |modify()|.
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp index 89d68d2..a10d26b 100644 --- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp +++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
@@ -89,10 +89,10 @@ return PlainTextRange::create(*editable, range); } -VisibleSelection createSelection(const size_t start, - const size_t end, - const bool isDirectional, - Element* element) { +SelectionInDOMTree createSelection(const size_t start, + const size_t end, + const bool isDirectional, + Element* element) { const EphemeralRange& startRange = PlainTextRange(0, static_cast<int>(start)).createRange(*element); DCHECK(startRange.isNotNull()); @@ -103,11 +103,11 @@ DCHECK(endRange.isNotNull()); const Position& endPosition = endRange.endPosition(); - const VisibleSelection& selection = - createVisibleSelection(SelectionInDOMTree::Builder() - .setBaseAndExtent(startPosition, endPosition) - .setIsDirectional(isDirectional) - .build()); + const SelectionInDOMTree& selection = + SelectionInDOMTree::Builder() + .setBaseAndExtent(startPosition, endPosition) + .setIsDirectional(isDirectional) + .build(); return selection; } @@ -255,10 +255,11 @@ } void TypingCommand::adjustSelectionAfterIncrementalInsertion( - TypingCommand* command, LocalFrame* frame, - const size_t start, - const size_t end) { + const size_t textLength) { + if (!isIncrementalInsertion()) + return; + // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets // needs to be audited. see http://crbug.com/590369 for more details. frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); @@ -266,13 +267,17 @@ Element* element = frame->selection().selection().rootEditableElement(); DCHECK(element); - const VisibleSelection& selection = createSelection( - start, end, command->endingSelection().isDirectional(), element); + const size_t end = m_selectionStart + textLength; + const size_t start = + compositionType() == TextCompositionUpdate ? m_selectionStart : end; + const SelectionInDOMTree& selection = + createSelection(start, end, endingSelection().isDirectional(), element); - if (selection != frame->selection().selection()) { - command->setEndingVisibleSelection(selection); - frame->selection().setSelection(selection); - } + if (selection == frame->selection().selection().asSelection()) + return; + + setEndingSelection(selection); + frame->selection().setSelection(selection); } // FIXME: We shouldn't need to take selectionForInsertion. It should be @@ -307,6 +312,9 @@ document.updateStyleAndLayoutIgnorePendingStylesheets(); const PlainTextRange selectionOffsets = getSelectionOffsets(frame); + if (selectionOffsets.isNull()) + return; + const size_t selectionStart = selectionOffsets.start(); // Set the starting and ending selection appropriately if we are using a // selection that is different from the current selection. In the future, we @@ -326,20 +334,9 @@ PreventSpellChecking); EditingState editingState; lastTypingCommand->m_isIncrementalInsertion = isIncrementalInsertion; + lastTypingCommand->m_selectionStart = selectionStart; lastTypingCommand->insertText(newText, options & SelectInsertedText, &editingState); - - if (editingState.isAborted()) - return; - - if (isIncrementalInsertion) { - const size_t newEnd = selectionOffsets.start() + newText.length(); - const size_t newStart = (compositionType == TextCompositionUpdate) - ? selectionOffsets.start() - : newEnd; - adjustSelectionAfterIncrementalInsertion(lastTypingCommand, frame, - newStart, newEnd); - } return; } @@ -351,23 +348,12 @@ command->setEndingVisibleSelection(selectionForInsertion); } command->m_isIncrementalInsertion = isIncrementalInsertion; - const bool aborted = !(command->apply()); + command->m_selectionStart = selectionStart; + command->apply(); if (changeSelection) { command->setEndingVisibleSelection(currentSelection); frame->selection().setSelection(currentSelection); - return; - } - - if (aborted) - return; - - if (isIncrementalInsertion) { - const size_t newEnd = selectionOffsets.start() + newText.length(); - const size_t newStart = (compositionType == TextCompositionUpdate) - ? selectionOffsets.start() - : newEnd; - adjustSelectionAfterIncrementalInsertion(command, frame, newStart, newEnd); } } @@ -509,6 +495,8 @@ void TypingCommand::insertText(const String& text, bool selectInsertedText, EditingState* editingState) { + m_textToInsert = text; + if (text.isEmpty()) { insertTextRunWithoutNewlines(text, selectInsertedText, editingState); return; @@ -524,11 +512,14 @@ size_t newline; while ((newline = text.find('\n', offset)) != kNotFound) { if (newline > offset) { - const bool notSelectInsertedText = false; - insertTextRunWithoutNewlines(text.substring(offset, newline - offset), - notSelectInsertedText, editingState); + const size_t insertionLength = newline - offset; + insertTextRunWithoutNewlines(text.substring(offset, insertionLength), + false, editingState); if (editingState->isAborted()) return; + + adjustSelectionAfterIncrementalInsertion(document().frame(), + insertionLength); } insertParagraphSeparator(editingState); @@ -540,12 +531,22 @@ if (!offset) { insertTextRunWithoutNewlines(text, selectInsertedText, editingState); + if (editingState->isAborted()) + return; + + adjustSelectionAfterIncrementalInsertion(document().frame(), text.length()); return; } if (text.length() > offset) { - insertTextRunWithoutNewlines(text.substring(offset, text.length() - offset), + const size_t insertionLength = text.length() - offset; + insertTextRunWithoutNewlines(text.substring(offset, insertionLength), selectInsertedText, editingState); + if (editingState->isAborted()) + return; + + adjustSelectionAfterIncrementalInsertion(document().frame(), + insertionLength); } } @@ -572,7 +573,6 @@ if (editingState->isAborted()) return; - m_textToInsert = text; typingAddedToOpenCommand(InsertText); }
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.h b/third_party/WebKit/Source/core/editing/commands/TypingCommand.h index 437980a..d17c8dc2e 100644 --- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.h +++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.h
@@ -95,10 +95,8 @@ void setCompositionType(TextCompositionType type) { m_compositionType = type; } - static void adjustSelectionAfterIncrementalInsertion(TypingCommand*, - LocalFrame*, - const size_t start, - const size_t end); + void adjustSelectionAfterIncrementalInsertion(LocalFrame*, + const size_t textLength); ETypingCommand commandTypeOfOpenCommand() const { return m_commandType; } TextCompositionType compositionType() const { return m_compositionType; } @@ -183,6 +181,7 @@ bool m_shouldPreventSpellChecking; bool m_isIncrementalInsertion; + size_t m_selectionStart; }; DEFINE_TYPE_CASTS(TypingCommand,
diff --git a/third_party/WebKit/Source/core/events/CompositionEvent.cpp b/third_party/WebKit/Source/core/events/CompositionEvent.cpp index 3cf803375..60a041a 100644 --- a/third_party/WebKit/Source/core/events/CompositionEvent.cpp +++ b/third_party/WebKit/Source/core/events/CompositionEvent.cpp
@@ -26,6 +26,8 @@ #include "core/events/CompositionEvent.h" +#include "core/input/InputDeviceCapabilities.h" + namespace blink { CompositionEvent::CompositionEvent() {} @@ -33,15 +35,15 @@ CompositionEvent::CompositionEvent(const AtomicString& type, AbstractView* view, const String& data) - : UIEvent( - type, - true, - true, - ComposedMode::Composed, - TimeTicks::Now(), - view, - 0, - InputDeviceCapabilities::doesntFireTouchEventsSourceCapabilities()), + : UIEvent(type, + true, + true, + ComposedMode::Composed, + TimeTicks::Now(), + view, + 0, + view ? view->getInputDeviceCapabilities()->firesTouchEvents(false) + : nullptr), m_data(data) {} CompositionEvent::CompositionEvent(const AtomicString& type,
diff --git a/third_party/WebKit/Source/core/events/KeyboardEvent.cpp b/third_party/WebKit/Source/core/events/KeyboardEvent.cpp index 6e6b8479..e7581e89 100644 --- a/third_party/WebKit/Source/core/events/KeyboardEvent.cpp +++ b/third_party/WebKit/Source/core/events/KeyboardEvent.cpp
@@ -25,6 +25,7 @@ #include "bindings/core/v8/DOMWrapperWorld.h" #include "bindings/core/v8/ScriptState.h" #include "core/editing/InputMethodController.h" +#include "core/input/InputDeviceCapabilities.h" #include "platform/WindowsKeyboardCodes.h" #include "public/platform/Platform.h" #include "public/platform/WebInputEvent.h" @@ -96,7 +97,9 @@ 0, static_cast<PlatformEvent::Modifiers>(key.modifiers()), TimeTicks::FromSeconds(key.timeStampSeconds()), - InputDeviceCapabilities::doesntFireTouchEventsSourceCapabilities()), + domWindow + ? domWindow->getInputDeviceCapabilities()->firesTouchEvents(false) + : nullptr), m_keyEvent(WTF::makeUnique<WebKeyboardEvent>(key)), // TODO(crbug.com/482880): Fix this initialization to lazy initialization. m_code(Platform::current()->domCodeStringFromEnum(key.domCode)),
diff --git a/third_party/WebKit/Source/core/events/MouseEvent.cpp b/third_party/WebKit/Source/core/events/MouseEvent.cpp index 5e68f976..9da39b5 100644 --- a/third_party/WebKit/Source/core/events/MouseEvent.cpp +++ b/third_party/WebKit/Source/core/events/MouseEvent.cpp
@@ -29,6 +29,7 @@ #include "core/frame/FrameView.h" #include "core/frame/LocalDOMWindow.h" #include "core/frame/LocalFrame.h" +#include "core/input/InputDeviceCapabilities.h" #include "core/layout/LayoutObject.h" #include "core/paint/PaintLayer.h" #include "core/svg/SVGElement.h" @@ -163,10 +164,10 @@ detail, static_cast<PlatformEvent::Modifiers>(event.modifiers()), TimeTicks::FromSeconds(event.timeStampSeconds()), - event.fromTouch() - ? InputDeviceCapabilities::firesTouchEventsSourceCapabilities() - : InputDeviceCapabilities:: - doesntFireTouchEventsSourceCapabilities()), + abstractView + ? abstractView->getInputDeviceCapabilities()->firesTouchEvents( + event.fromTouch()) + : nullptr), m_screenLocation(event.globalX, event.globalY), m_movementDelta(flooredIntPoint(event.movementInRootFrame())), m_positionType(PositionType::Position), @@ -207,10 +208,10 @@ detail, modifiers, platformTimeStamp, - syntheticEventType == FromTouch - ? InputDeviceCapabilities::firesTouchEventsSourceCapabilities() - : InputDeviceCapabilities:: - doesntFireTouchEventsSourceCapabilities()), + abstractView + ? abstractView->getInputDeviceCapabilities()->firesTouchEvents( + syntheticEventType == FromTouch) + : nullptr), m_screenLocation(screenX, screenY), m_movementDelta(movementX, movementY), m_positionType(syntheticEventType == Positionless
diff --git a/third_party/WebKit/Source/core/events/TouchEvent.cpp b/third_party/WebKit/Source/core/events/TouchEvent.cpp index 27306e5..066d2c9d 100644 --- a/third_party/WebKit/Source/core/events/TouchEvent.cpp +++ b/third_party/WebKit/Source/core/events/TouchEvent.cpp
@@ -33,6 +33,7 @@ #include "core/frame/FrameView.h" #include "core/frame/LocalDOMWindow.h" #include "core/html/HTMLElement.h" +#include "core/input/InputDeviceCapabilities.h" #include "core/inspector/ConsoleMessage.h" #include "platform/Histogram.h" @@ -218,7 +219,8 @@ 0, static_cast<PlatformEvent::Modifiers>(event.modifiers()), TimeTicks::FromSeconds(event.timeStampSeconds()), - InputDeviceCapabilities::firesTouchEventsSourceCapabilities()), + view ? view->getInputDeviceCapabilities()->firesTouchEvents(true) + : nullptr), m_touches(touches), m_targetTouches(targetTouches), m_changedTouches(changedTouches),
diff --git a/third_party/WebKit/Source/core/events/UIEvent.cpp b/third_party/WebKit/Source/core/events/UIEvent.cpp index af8ea4ba..178350dc 100644 --- a/third_party/WebKit/Source/core/events/UIEvent.cpp +++ b/third_party/WebKit/Source/core/events/UIEvent.cpp
@@ -22,6 +22,8 @@ #include "core/events/UIEvent.h" +#include "core/input/InputDeviceCapabilities.h" + namespace blink { UIEvent::UIEvent() : m_detail(0), m_sourceCapabilities(nullptr) {}
diff --git a/third_party/WebKit/Source/core/events/UIEvent.h b/third_party/WebKit/Source/core/events/UIEvent.h index 222147eb..584b976 100644 --- a/third_party/WebKit/Source/core/events/UIEvent.h +++ b/third_party/WebKit/Source/core/events/UIEvent.h
@@ -29,10 +29,11 @@ #include "core/events/EventDispatchMediator.h" #include "core/events/UIEventInit.h" #include "core/frame/DOMWindow.h" -#include "core/input/InputDeviceCapabilities.h" namespace blink { +class InputDeviceCapabilities; + // FIXME: Get rid of this type alias. using AbstractView = DOMWindow;
diff --git a/third_party/WebKit/Source/core/fileapi/FileReader.cpp b/third_party/WebKit/Source/core/fileapi/FileReader.cpp index 68f23f6..94c36ca 100644 --- a/third_party/WebKit/Source/core/fileapi/FileReader.cpp +++ b/third_party/WebKit/Source/core/fileapi/FileReader.cpp
@@ -343,7 +343,6 @@ ThrottlingController::FinishReaderType finalStep = ThrottlingController::removeReader(getExecutionContext(), this); - fireEvent(EventTypeNames::error); fireEvent(EventTypeNames::abort); fireEvent(EventTypeNames::loadend);
diff --git a/third_party/WebKit/Source/core/frame/DOMWindow.cpp b/third_party/WebKit/Source/core/frame/DOMWindow.cpp index 4c1849a6..6a8dfce8 100644 --- a/third_party/WebKit/Source/core/frame/DOMWindow.cpp +++ b/third_party/WebKit/Source/core/frame/DOMWindow.cpp
@@ -4,6 +4,7 @@ #include "core/frame/DOMWindow.h" +#include <memory> #include "core/dom/Document.h" #include "core/dom/ExecutionContext.h" #include "core/dom/SecurityContext.h" @@ -15,6 +16,7 @@ #include "core/frame/Location.h" #include "core/frame/Settings.h" #include "core/frame/UseCounter.h" +#include "core/input/InputDeviceCapabilities.h" #include "core/inspector/ConsoleMessage.h" #include "core/inspector/InspectorInstrumentation.h" #include "core/loader/MixedContentChecker.h" @@ -24,7 +26,6 @@ #include "platform/weborigin/KURL.h" #include "platform/weborigin/SecurityOrigin.h" #include "platform/weborigin/Suborigin.h" -#include <memory> namespace blink { @@ -425,8 +426,15 @@ page->focusController().focusDocumentView(frame(), true /* notifyEmbedder */); } +InputDeviceCapabilitiesConstants* DOMWindow::getInputDeviceCapabilities() { + if (!m_inputCapabilities) + m_inputCapabilities = new InputDeviceCapabilitiesConstants; + return m_inputCapabilities; +} + DEFINE_TRACE(DOMWindow) { visitor->trace(m_frame); + visitor->trace(m_inputCapabilities); visitor->trace(m_location); EventTargetWithInlineData::trace(visitor); }
diff --git a/third_party/WebKit/Source/core/frame/DOMWindow.h b/third_party/WebKit/Source/core/frame/DOMWindow.h index dfd491f..c1d2bb8 100644 --- a/third_party/WebKit/Source/core/frame/DOMWindow.h +++ b/third_party/WebKit/Source/core/frame/DOMWindow.h
@@ -17,6 +17,7 @@ namespace blink { class Document; +class InputDeviceCapabilitiesConstants; class Location; class LocalDOMWindow; class MessageEvent; @@ -101,6 +102,8 @@ bool isSecureContext() const; + InputDeviceCapabilitiesConstants* getInputDeviceCapabilities(); + protected: explicit DOMWindow(Frame&); @@ -112,6 +115,7 @@ private: Member<Frame> m_frame; + Member<InputDeviceCapabilitiesConstants> m_inputCapabilities; mutable Member<Location> m_location; // Set to true when close() has been called. Needed for
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp index 9aa2afd8..94b9738 100644 --- a/third_party/WebKit/Source/core/frame/FrameView.cpp +++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -26,6 +26,7 @@ #include "core/frame/FrameView.h" +#include <memory> #include "core/HTMLNames.h" #include "core/MediaTypeNames.h" #include "core/animation/DocumentAnimations.h" @@ -40,6 +41,7 @@ #include "core/dom/ResizeObserverController.h" #include "core/dom/StyleChangeReason.h" #include "core/dom/TaskRunnerHelper.h" +#include "core/editing/DragCaret.h" #include "core/editing/EditingUtilities.h" #include "core/editing/FrameSelection.h" #include "core/editing/RenderedPosition.h" @@ -93,6 +95,7 @@ #include "core/page/scrolling/RootScrollerUtil.h" #include "core/page/scrolling/ScrollingCoordinator.h" #include "core/page/scrolling/TopDocumentRootScrollerController.h" +#include "core/paint/BlockPaintInvalidator.h" #include "core/paint/FramePainter.h" #include "core/paint/PaintLayer.h" #include "core/paint/PaintTiming.h" @@ -129,7 +132,6 @@ #include "wtf/CurrentTime.h" #include "wtf/PtrUtil.h" #include "wtf/StdLibExtras.h" -#include <memory> // Used to check for dirty layouts violating document lifecycle rules. // If arg evaluates to true, the program will continue. If arg evaluates to @@ -395,9 +397,9 @@ if (hasScrollbar) { m_hBar = createScrollbar(HorizontalScrollbar); m_scrollableArea->layoutBox()->document().view()->addChild(m_hBar.get()); + m_hBarIsAttached = 1; m_scrollableArea->didAddScrollbar(*m_hBar, HorizontalScrollbar); m_hBar->styleChanged(); - m_hBarIsAttached = 1; } else { m_hBarIsAttached = 0; destroyScrollbar(HorizontalScrollbar); @@ -413,9 +415,9 @@ if (hasScrollbar) { m_vBar = createScrollbar(VerticalScrollbar); m_scrollableArea->layoutBox()->document().view()->addChild(m_vBar.get()); + m_vBarIsAttached = 1; m_scrollableArea->didAddScrollbar(*m_vBar, VerticalScrollbar); m_vBar->styleChanged(); - m_vBarIsAttached = 1; } else { m_vBarIsAttached = 0; destroyScrollbar(VerticalScrollbar); @@ -1340,8 +1342,6 @@ RELEASE_ASSERT(!layoutViewItem().isNull()); if (!RuntimeEnabledFeatures::rootLayerScrollingEnabled()) invalidatePaintOfScrollControlsIfNeeded(paintInvalidationState); - - m_frame->selection().invalidateCaretRect(); } void FrameView::setNeedsPaintPropertyUpdate() { @@ -3249,6 +3249,9 @@ if (frame().document()->hasFinishedParsing() && frame().loader().stateMachine()->committedFirstRealDocumentLoad()) m_isVisuallyNonEmpty = true; + + frame().selection().updateStyleAndLayoutIfNeeded(); + frame().page()->dragCaret().updateStyleAndLayoutIfNeeded(); } void FrameView::invalidateTreeIfNeededRecursive() { @@ -3268,8 +3271,7 @@ // throttled even though we are (e.g., it didn't compute its visibility yet). if (shouldThrottleRendering()) return; - TRACE_EVENT1("blink", "FrameView::invalidateTreeIfNeededRecursive", "root", - layoutView()->debugName().ascii()); + TRACE_EVENT0("blink", "FrameView::invalidateTreeIfNeededRecursiveInternal"); Vector<const LayoutObject*> pendingDelayedPaintInvalidations; PaintInvalidationState rootPaintInvalidationState( @@ -3282,8 +3284,8 @@ // because // - the frame is a detached frame; or // - it didn't need paint invalidation. - // We need to call invalidateTreeIfNeededRecursive() for such frames to finish - // required paint invalidation and advance their life cycle state. + // We need to call invalidateTreeIfNeededRecursiveInternal() for such frames + // to finish required paint invalidation and advance their life cycle state. for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) { if (child->isLocalFrame()) {
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h index 5579ffa..7d2b9f1b 100644 --- a/third_party/WebKit/Source/core/frame/UseCounter.h +++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -1454,6 +1454,8 @@ V8TextDetector_Detect_Method = 1801, CSSValueOnDemand = 1802, ServiceWorkerNavigationPreload = 1803, + FullscreenRequestWithPendingElement = 1804, + HTMLIFrameElementAllowfullscreenAttributeSetAfterContentLoad = 1805, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/WebKit/Source/core/html/BUILD.gn b/third_party/WebKit/Source/core/html/BUILD.gn index 0fab038..e8a12a5 100644 --- a/third_party/WebKit/Source/core/html/BUILD.gn +++ b/third_party/WebKit/Source/core/html/BUILD.gn
@@ -393,8 +393,6 @@ "parser/HTMLParserScriptRunner.cpp", "parser/HTMLParserScriptRunner.h", "parser/HTMLParserScriptRunnerHost.h", - "parser/HTMLParserThread.cpp", - "parser/HTMLParserThread.h", "parser/HTMLPreloadScanner.cpp", "parser/HTMLPreloadScanner.h", "parser/HTMLResourcePreloader.cpp",
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp index e41d489..eba91ca 100644 --- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -27,6 +27,9 @@ #include "core/html/HTMLCanvasElement.h" +#include <math.h> +#include <v8.h> +#include <memory> #include "bindings/core/v8/ExceptionMessages.h" #include "bindings/core/v8/ExceptionState.h" #include "bindings/core/v8/ScriptController.h" @@ -53,6 +56,7 @@ #include "core/html/canvas/CanvasRenderingContext.h" #include "core/html/canvas/CanvasRenderingContextFactory.h" #include "core/imagebitmap/ImageBitmapOptions.h" +#include "core/inspector/InspectorInstrumentation.h" #include "core/layout/HitTestCanvasResult.h" #include "core/layout/LayoutHTMLCanvas.h" #include "core/layout/api/LayoutViewItem.h" @@ -77,9 +81,6 @@ #include "public/platform/WebTraceLocation.h" #include "wtf/CheckedNumeric.h" #include "wtf/PtrUtil.h" -#include <math.h> -#include <memory> -#include <v8.h> namespace blink { @@ -271,6 +272,8 @@ if (!m_context) return nullptr; + InspectorInstrumentation::didCreateCanvasContext(&document()); + if (m_context->is3d()) { updateExternallyAllocatedMemory(); }
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp b/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp index 14b69808..0ac2d29 100644 --- a/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp
@@ -125,8 +125,17 @@ } else if (name == allowfullscreenAttr) { bool oldAllowFullscreen = m_allowFullscreen; m_allowFullscreen = !value.isNull(); - if (m_allowFullscreen != oldAllowFullscreen) + if (m_allowFullscreen != oldAllowFullscreen) { + // TODO(iclelland): Remove this use counter when the allowfullscreen + // attribute state is snapshotted on document creation. crbug.com/682282 + if (m_allowFullscreen && contentFrame()) { + UseCounter::count( + document(), + UseCounter:: + HTMLIFrameElementAllowfullscreenAttributeSetAfterContentLoad); + } frameOwnerPropertiesChanged(); + } } else if (name == allowpaymentrequestAttr) { bool oldAllowPaymentRequest = m_allowPaymentRequest; m_allowPaymentRequest = !value.isNull();
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp index 097040c..9156bba5 100644 --- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
@@ -829,11 +829,9 @@ // 4.6.2 - Take pending play promises and reject pending play promises // with the result and an "AbortError" DOMException. - if (!ScriptForbiddenScope::isScriptForbidden()) { - rejectPlayPromises( - AbortError, - "The play() request was interrupted by a new load request."); - } + rejectPlayPromises( + AbortError, + "The play() request was interrupted by a new load request."); } // 4.7 - If seeking is true, set it to false.
diff --git a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp index ad5881b..bed8a48 100644 --- a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
@@ -60,6 +60,7 @@ #include "core/html/HTMLOptionElement.h" #include "core/html/forms/FormController.h" #include "core/input/EventHandler.h" +#include "core/input/InputDeviceCapabilities.h" #include "core/inspector/ConsoleMessage.h" #include "core/layout/HitTestRequest.h" #include "core/layout/HitTestResult.h" @@ -1351,10 +1352,8 @@ toMouseEvent(event)->button() == static_cast<short>(WebPointerProperties::Button::Left)) { InputDeviceCapabilities* sourceCapabilities = - toMouseEvent(event)->fromTouch() - ? InputDeviceCapabilities::firesTouchEventsSourceCapabilities() - : InputDeviceCapabilities:: - doesntFireTouchEventsSourceCapabilities(); + document().domWindow()->getInputDeviceCapabilities()->firesTouchEvents( + toMouseEvent(event)->fromTouch()); focus(FocusParams(SelectionBehaviorOnFocus::Restore, WebFocusTypeNone, sourceCapabilities)); if (layoutObject() && layoutObject()->isMenuList() &&
diff --git a/third_party/WebKit/Source/core/html/forms/MultipleFieldsTemporalInputTypeView.cpp b/third_party/WebKit/Source/core/html/forms/MultipleFieldsTemporalInputTypeView.cpp index 2094e3a6..184f3b7f 100644 --- a/third_party/WebKit/Source/core/html/forms/MultipleFieldsTemporalInputTypeView.cpp +++ b/third_party/WebKit/Source/core/html/forms/MultipleFieldsTemporalInputTypeView.cpp
@@ -346,7 +346,7 @@ RefPtr<ComputedStyle> style = ComputedStyle::clone(*originalStyle); style->setDirection(contentDirection); style->setDisplay(newDisplay); - style->setUnique(); + style->setUnique(true); return style.release(); }
diff --git a/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp b/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp index e3b0069e..4535038 100644 --- a/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp +++ b/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp
@@ -98,6 +98,9 @@ const SegmentedString& source) { // We are just interested in @import rules, no need for real tokenization here // Searching for other types of resources is probably low payoff. + // If we ever decide to preload fonts, we also need to change + // ResourceFetcher::resourceNeedsLoad to immediately load speculative font + // preloads. switch (m_state) { case Initial: if (isHTMLSpace<UChar>(c))
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp index 6569f2df..5a886100 100644 --- a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp +++ b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp
@@ -39,7 +39,6 @@ #include "core/html/parser/BackgroundHTMLParser.h" #include "core/html/parser/HTMLParserScheduler.h" #include "core/html/parser/HTMLParserScriptRunner.h" -#include "core/html/parser/HTMLParserThread.h" #include "core/html/parser/HTMLResourcePreloader.h" #include "core/html/parser/HTMLTreeBuilder.h" #include "core/inspector/InspectorInstrumentation.h"
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLParserThread.cpp b/third_party/WebKit/Source/core/html/parser/HTMLParserThread.cpp deleted file mode 100644 index 891d157..0000000 --- a/third_party/WebKit/Source/core/html/parser/HTMLParserThread.cpp +++ /dev/null
@@ -1,94 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -#include "core/html/parser/HTMLParserThread.h" - -#include "platform/CrossThreadFunctional.h" -#include "platform/WaitableEvent.h" -#include "platform/heap/SafePoint.h" -#include "public/platform/Platform.h" -#include "public/platform/WebTraceLocation.h" - -namespace blink { - -static HTMLParserThread* s_sharedThread = nullptr; - -HTMLParserThread::HTMLParserThread() {} - -HTMLParserThread::~HTMLParserThread() {} - -void HTMLParserThread::init() { - ASSERT(!s_sharedThread); - s_sharedThread = new HTMLParserThread; -} - -void HTMLParserThread::setupHTMLParserThread() { - ASSERT(m_thread); - m_thread->initialize(); -} - -void HTMLParserThread::shutdown() { - ASSERT(isMainThread()); - ASSERT(s_sharedThread); - // currentThread will always be non-null in production, but can be null in - // Chromium unit tests. - if (Platform::current()->currentThread() && s_sharedThread->m_thread) { - WaitableEvent waitableEvent; - s_sharedThread->postTask( - crossThreadBind(&HTMLParserThread::cleanupHTMLParserThread, - crossThreadUnretained(s_sharedThread), - crossThreadUnretained(&waitableEvent))); - waitableEvent.wait(); - } - delete s_sharedThread; - s_sharedThread = nullptr; -} - -void HTMLParserThread::cleanupHTMLParserThread(WaitableEvent* waitableEvent) { - m_thread->shutdown(); - waitableEvent->signal(); -} - -HTMLParserThread* HTMLParserThread::shared() { - return s_sharedThread; -} - -void HTMLParserThread::postTask(std::unique_ptr<CrossThreadClosure> closure) { - ASSERT(isMainThread()); - if (!m_thread) { - m_thread = WebThreadSupportingGC::create("HTMLParserThread"); - postTask(crossThreadBind(&HTMLParserThread::setupHTMLParserThread, - crossThreadUnretained(this))); - } - - m_thread->postTask(BLINK_FROM_HERE, std::move(closure)); -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLParserThread.h b/third_party/WebKit/Source/core/html/parser/HTMLParserThread.h deleted file mode 100644 index 4f988d8..0000000 --- a/third_party/WebKit/Source/core/html/parser/HTMLParserThread.h +++ /dev/null
@@ -1,66 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -#ifndef HTMLParserThread_h -#define HTMLParserThread_h - -#include "core/CoreExport.h" -#include "platform/WaitableEvent.h" -#include "platform/WebThreadSupportingGC.h" -#include "wtf/Allocator.h" -#include "wtf/Functional.h" -#include <memory> - -namespace blink { - -class CORE_EXPORT HTMLParserThread { - USING_FAST_MALLOC(HTMLParserThread); - - public: - static void init(); - static void shutdown(); - - // It is an error to call shared() before init() or after shutdown(); - static HTMLParserThread* shared(); - - void postTask(std::unique_ptr<CrossThreadClosure>); - - private: - HTMLParserThread(); - ~HTMLParserThread(); - void setupHTMLParserThread(); - void cleanupHTMLParserThread(WaitableEvent*); - - std::unique_ptr<WebThreadSupportingGC> m_thread; -}; - -} // namespace blink - -#endif // HTMLParserThread_h
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLParserThreadTest.cpp b/third_party/WebKit/Source/core/html/parser/HTMLParserThreadTest.cpp deleted file mode 100644 index bf551ee..0000000 --- a/third_party/WebKit/Source/core/html/parser/HTMLParserThreadTest.cpp +++ /dev/null
@@ -1,34 +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 "core/html/parser/HTMLParserThread.h" - -#include "platform/RuntimeEnabledFeatures.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace blink { - -TEST(HTMLParserThreadTest, Init) { - // The harness has not initialized the parser thread, due to - // RuntimeEnabledFeatures gating. - ASSERT_FALSE(HTMLParserThread::shared()); - HTMLParserThread::init(); - ASSERT_TRUE(HTMLParserThread::shared()); - HTMLParserThread::shutdown(); -} - -TEST(HTMLParserThreadTest, ShutdownStartup) { - // The harness has not initialized the parser thread, due to - // RuntimeEnabledFeatures gating. - ASSERT_FALSE(HTMLParserThread::shared()); - HTMLParserThread::init(); - ASSERT_TRUE(HTMLParserThread::shared()); - - HTMLParserThread::shutdown(); - ASSERT_FALSE(HTMLParserThread::shared()); - HTMLParserThread::init(); - ASSERT_TRUE(HTMLParserThread::shared()); -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/core/html/parser/PreloadRequest.cpp b/third_party/WebKit/Source/core/html/parser/PreloadRequest.cpp index e8d296e..aefdfa3 100644 --- a/third_party/WebKit/Source/core/html/parser/PreloadRequest.cpp +++ b/third_party/WebKit/Source/core/html/parser/PreloadRequest.cpp
@@ -74,7 +74,7 @@ request.setCharset( m_charset.isEmpty() ? document->characterSet().getString() : m_charset); } - request.setForPreload(true, m_discoveryTime); + request.setSpeculativePreload(true, m_discoveryTime); return document->loader()->startPreload(m_resourceType, request); }
diff --git a/third_party/WebKit/Source/core/html/shadow/DateTimeEditElement.cpp b/third_party/WebKit/Source/core/html/shadow/DateTimeEditElement.cpp index 38d5e27..0cc8b09 100644 --- a/third_party/WebKit/Source/core/html/shadow/DateTimeEditElement.cpp +++ b/third_party/WebKit/Source/core/html/shadow/DateTimeEditElement.cpp
@@ -581,7 +581,7 @@ } } style->setWidth(Length(ceilf(width), Fixed)); - style->setUnique(); + style->setUnique(true); return style.release(); }
diff --git a/third_party/WebKit/Source/core/html/shadow/TextControlInnerElements.cpp b/third_party/WebKit/Source/core/html/shadow/TextControlInnerElements.cpp index 7ba751e3..94e72359 100644 --- a/third_party/WebKit/Source/core/html/shadow/TextControlInnerElements.cpp +++ b/third_party/WebKit/Source/core/html/shadow/TextControlInnerElements.cpp
@@ -87,7 +87,7 @@ // We don't want the shadow dom to be editable, so we set this block to // read-only in case the input itself is editable. style->setUserModify(READ_ONLY); - style->setUnique(); + style->setUnique(true); if (const ComputedStyle* parentStyle = parentComputedStyle()) StyleAdjuster::adjustStyleForAlignment(*style, *parentStyle);
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp index fa417ad6..4736b6f4 100644 --- a/third_party/WebKit/Source/core/input/EventHandler.cpp +++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -678,9 +678,11 @@ HitTestResult hitTestResult = EventHandlingUtil::hitTestResultInFrame( m_frame, documentPoint, HitTestRequest::ReadOnly); InputDeviceCapabilities* sourceCapabilities = - mouseEvent.fromTouch() - ? InputDeviceCapabilities::firesTouchEventsSourceCapabilities() - : InputDeviceCapabilities::doesntFireTouchEventsSourceCapabilities(); + m_frame->document() + ->domWindow() + ->getInputDeviceCapabilities() + ->firesTouchEvents(mouseEvent.fromTouch()); + if (eventResult == WebInputEventResult::NotHandled) { eventResult = m_mouseEventManager->handleMouseFocus(hitTestResult, sourceCapabilities);
diff --git a/third_party/WebKit/Source/core/input/GestureManager.cpp b/third_party/WebKit/Source/core/input/GestureManager.cpp index fc76f4b..4eddb518 100644 --- a/third_party/WebKit/Source/core/input/GestureManager.cpp +++ b/third_party/WebKit/Source/core/input/GestureManager.cpp
@@ -14,6 +14,7 @@ #include "core/frame/VisualViewport.h" #include "core/input/EventHandler.h" #include "core/input/EventHandlingUtil.h" +#include "core/input/InputDeviceCapabilities.h" #include "core/page/ChromeClient.h" #include "core/page/Page.h" @@ -213,13 +214,17 @@ currentHitTest.innerNode(), currentHitTest.canvasRegionId(), EventTypeNames::mousedown, fakeMouseDown); m_selectionController->initializeSelectionState(); - if (mouseDownEventResult == WebInputEventResult::NotHandled) + if (mouseDownEventResult == WebInputEventResult::NotHandled) { mouseDownEventResult = m_mouseEventManager->handleMouseFocus( - currentHitTest, - InputDeviceCapabilities::firesTouchEventsSourceCapabilities()); - if (mouseDownEventResult == WebInputEventResult::NotHandled) + currentHitTest, m_frame->document() + ->domWindow() + ->getInputDeviceCapabilities() + ->firesTouchEvents(true)); + } + if (mouseDownEventResult == WebInputEventResult::NotHandled) { mouseDownEventResult = m_mouseEventManager->handleMousePressEvent( MouseEventWithHitTestResults(fakeMouseDown, currentHitTest)); + } } if (currentHitTest.innerNode()) { @@ -393,9 +398,11 @@ MouseEventWithHitTestResults mev = m_frame->document()->performMouseEventHitTest(request, documentPoint, mouseEvent); - m_mouseEventManager->handleMouseFocus( - mev.hitTestResult(), - InputDeviceCapabilities::firesTouchEventsSourceCapabilities()); + m_mouseEventManager->handleMouseFocus(mev.hitTestResult(), + m_frame->document() + ->domWindow() + ->getInputDeviceCapabilities() + ->firesTouchEvents(true)); } return m_frame->eventHandler().sendContextMenuEvent(mouseEvent); }
diff --git a/third_party/WebKit/Source/core/input/InputDeviceCapabilities.cpp b/third_party/WebKit/Source/core/input/InputDeviceCapabilities.cpp index 63309b8..f112e2aa 100644 --- a/third_party/WebKit/Source/core/input/InputDeviceCapabilities.cpp +++ b/third_party/WebKit/Source/core/input/InputDeviceCapabilities.cpp
@@ -15,18 +15,16 @@ m_firesTouchEvents = initializer.firesTouchEvents(); } -InputDeviceCapabilities* -InputDeviceCapabilities::firesTouchEventsSourceCapabilities() { - DEFINE_STATIC_LOCAL(InputDeviceCapabilities, instance, - (InputDeviceCapabilities::create(true))); - return &instance; -} - -InputDeviceCapabilities* -InputDeviceCapabilities::doesntFireTouchEventsSourceCapabilities() { - DEFINE_STATIC_LOCAL(InputDeviceCapabilities, instance, - (InputDeviceCapabilities::create(false))); - return &instance; +InputDeviceCapabilities* InputDeviceCapabilitiesConstants::firesTouchEvents( + bool firesTouch) { + if (firesTouch) { + if (!m_firesTouchEvents) + m_firesTouchEvents = InputDeviceCapabilities::create(true); + return m_firesTouchEvents; + } + if (!m_doesntFireTouchEvents) + m_doesntFireTouchEvents = InputDeviceCapabilities::create(false); + return m_doesntFireTouchEvents; } } // namespace blink
diff --git a/third_party/WebKit/Source/core/input/InputDeviceCapabilities.h b/third_party/WebKit/Source/core/input/InputDeviceCapabilities.h index f869a69..d8731f3 100644 --- a/third_party/WebKit/Source/core/input/InputDeviceCapabilities.h +++ b/third_party/WebKit/Source/core/input/InputDeviceCapabilities.h
@@ -17,14 +17,6 @@ DEFINE_WRAPPERTYPEINFO(); public: - // This return a static local InputDeviceCapabilities pointer which has - // firesTouchEvents set to be true. - static InputDeviceCapabilities* firesTouchEventsSourceCapabilities(); - - // This return a static local InputDeviceCapabilities pointer which has - // firesTouchEvents set to be false. - static InputDeviceCapabilities* doesntFireTouchEventsSourceCapabilities(); - static InputDeviceCapabilities* create(bool firesTouchEvents) { return new InputDeviceCapabilities(firesTouchEvents); } @@ -48,6 +40,30 @@ bool m_firesTouchEvents; }; +// Grouping constant-valued InputDeviceCapabilities objects together, +// which is kept and used by each 'view' (DOMWindow) that dispatches +// events parameterized over InputDeviceCapabilities. +// +// TODO(sof): lazily instantiate InputDeviceCapabilities instances upon +// UIEvent access instead. This would allow internal tracking of such +// capabilities by value. +class InputDeviceCapabilitiesConstants final + : public GarbageCollected<InputDeviceCapabilitiesConstants> { + public: + // Returns an InputDeviceCapabilities which has + // |firesTouchEvents| set to value of |firesTouch|. + InputDeviceCapabilities* firesTouchEvents(bool firesTouch); + + DEFINE_INLINE_TRACE() { + visitor->trace(m_firesTouchEvents); + visitor->trace(m_doesntFireTouchEvents); + } + + private: + Member<InputDeviceCapabilities> m_firesTouchEvents; + Member<InputDeviceCapabilities> m_doesntFireTouchEvents; +}; + } // namespace blink #endif // InputDeviceCapabilities_h
diff --git a/third_party/WebKit/Source/core/input/KeyboardEventManager.cpp b/third_party/WebKit/Source/core/input/KeyboardEventManager.cpp index c27e4239..a7076a8 100644 --- a/third_party/WebKit/Source/core/input/KeyboardEventManager.cpp +++ b/third_party/WebKit/Source/core/input/KeyboardEventManager.cpp
@@ -11,6 +11,7 @@ #include "core/html/HTMLDialogElement.h" #include "core/input/EventHandler.h" #include "core/input/EventHandlingUtil.h" +#include "core/input/InputDeviceCapabilities.h" #include "core/input/ScrollManager.h" #include "core/layout/LayoutObject.h" #include "core/layout/LayoutTextControlSingleLine.h" @@ -394,9 +395,11 @@ if (m_frame->document()->inDesignMode()) return; - if (page->focusController().advanceFocus( - focusType, - InputDeviceCapabilities::doesntFireTouchEventsSourceCapabilities())) + if (page->focusController().advanceFocus(focusType, + m_frame->document() + ->domWindow() + ->getInputDeviceCapabilities() + ->firesTouchEvents(false))) event->setDefaultHandled(); }
diff --git a/third_party/WebKit/Source/core/input/TouchEventManager.cpp b/third_party/WebKit/Source/core/input/TouchEventManager.cpp index 6561639..149cff36 100644 --- a/third_party/WebKit/Source/core/input/TouchEventManager.cpp +++ b/third_party/WebKit/Source/core/input/TouchEventManager.cpp
@@ -62,6 +62,18 @@ TouchEventDispatchResultTypeMax, }; +bool IsTouchSequenceStart(const WebTouchEvent& event) { + if (!event.touchesLength) + return false; + if (event.type() != WebInputEvent::TouchStart) + return false; + for (size_t i = 0; i < event.touchesLength; ++i) { + if (event.touches[i].state != blink::WebTouchPoint::StatePressed) + return false; + } + return true; +} + // Defining this class type local to dispatchTouchEvents() and annotating // it with STACK_ALLOCATED(), runs into MSVC(VS 2013)'s C4822 warning // that the local class doesn't provide a local definition for 'operator new'. @@ -95,6 +107,7 @@ m_targetForTouchID.clear(); m_regionForTouchID.clear(); m_touchPressed = false; + m_suppressingTouchmovesWithinSlop = false; m_currentTouchAction = TouchActionAuto; } @@ -113,6 +126,22 @@ // http://www.w3.org/TR/touch-events/#touchevent-interface for how these // lists fit together. + // Suppress all the touch moves in the slop region. + if (IsTouchSequenceStart(event)) + m_suppressingTouchmovesWithinSlop = true; + + if (event.type() == WebInputEvent::TouchEnd || + event.type() == WebInputEvent::TouchCancel || event.touchesLength > 1) { + m_suppressingTouchmovesWithinSlop = false; + } + + if (m_suppressingTouchmovesWithinSlop && + event.type() == WebInputEvent::TouchMove) { + if (!event.movedBeyondSlopRegion) + return WebInputEventResult::HandledSuppressed; + m_suppressingTouchmovesWithinSlop = false; + } + // Holds the complete set of touches on the screen. TouchList* touches = TouchList::create();
diff --git a/third_party/WebKit/Source/core/input/TouchEventManager.h b/third_party/WebKit/Source/core/input/TouchEventManager.h index 123ac14a..2be2d4df 100644 --- a/third_party/WebKit/Source/core/input/TouchEventManager.h +++ b/third_party/WebKit/Source/core/input/TouchEventManager.h
@@ -95,6 +95,7 @@ Member<Document> m_touchSequenceDocument; bool m_touchPressed; + bool m_suppressingTouchmovesWithinSlop; // The current touch action, computed on each touch start and is // a union of all touches. Reset when all touches are released.
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp index 8787d1e..931f6e2 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp
@@ -2049,7 +2049,7 @@ frontend()->characterDataModified(id, characterData->data()); } -Member<InspectorRevalidateDOMTask> InspectorDOMAgent::revalidateTask() { +InspectorRevalidateDOMTask* InspectorDOMAgent::revalidateTask() { if (!m_revalidateTask) m_revalidateTask = new InspectorRevalidateDOMTask(this); return m_revalidateTask.get();
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.h b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.h index 0d9d1874..e5f9cbc5 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.h +++ b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.h
@@ -328,7 +328,7 @@ Response pushDocumentUponHandlelessOperation(); - Member<InspectorRevalidateDOMTask> revalidateTask(); + InspectorRevalidateDOMTask* revalidateTask(); v8::Isolate* m_isolate; Member<InspectedFrames> m_inspectedFrames;
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.cpp index afdd56b..05e4a437 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.cpp
@@ -63,6 +63,7 @@ static const char webglWarningFiredEventName[] = "webglWarningFired"; static const char webglErrorNameProperty[] = "webglErrorName"; static const char scriptBlockedByCSPEventName[] = "scriptBlockedByCSP"; +static const char canvasContextCreatedEventName[] = "canvasContextCreated"; namespace DOMDebuggerAgentState { static const char eventListenerBreakpoints[] = "eventListenerBreakpoints"; @@ -774,6 +775,11 @@ toV8InspectorStringView(json)); } +void InspectorDOMDebuggerAgent::didCreateCanvasContext() { + pauseOnNativeEventIfNeeded( + preparePauseOnNativeEventData(canvasContextCreatedEventName, 0), true); +} + void InspectorDOMDebuggerAgent::didAddBreakpoint() { if (m_state->booleanProperty(DOMDebuggerAgentState::enabled, false)) return;
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.h b/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.h index f0eb05f..1656078 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.h +++ b/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.h
@@ -90,6 +90,7 @@ void didRemoveDOMNode(Node*); void willModifyDOMAttr(Element*, const AtomicString&, const AtomicString&); void willSendXMLHttpOrFetchNetworkRequest(const String& url); + void didCreateCanvasContext(); void didFireWebGLError(const String& errorName); void didFireWebGLWarning(); void didFireWebGLErrorOrWarning(const String& message);
diff --git a/third_party/WebKit/Source/core/inspector/InspectorInputAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorInputAgent.cpp index 2bf479a..eeba239 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorInputAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorInputAgent.cpp
@@ -112,6 +112,7 @@ m_type = type; m_modifiers = modifiers; m_timeStampSeconds = timestamp.InSeconds(); + movedBeyondSlopRegion = true; } void append(const blink::WebTouchPoint& point) {
diff --git a/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.idl b/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.idl index b463a8b8..255196cd 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.idl +++ b/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.idl
@@ -126,6 +126,9 @@ void willSendXMLHttpOrFetchNetworkRequest(ExecutionContext*, const String& url); [DOMDebugger] + void didCreateCanvasContext(Document*); + + [DOMDebugger] void didFireWebGLError(Element*, const String& errorName); [DOMDebugger]
diff --git a/third_party/WebKit/Source/core/layout/Grid.cpp b/third_party/WebKit/Source/core/layout/Grid.cpp index aa65a6c0..580e1a1 100644 --- a/third_party/WebKit/Source/core/layout/Grid.cpp +++ b/third_party/WebKit/Source/core/layout/Grid.cpp
@@ -81,6 +81,10 @@ void Grid::setAutoRepeatTracks(size_t autoRepeatRows, size_t autoRepeatColumns) { + DCHECK_GE(static_cast<unsigned>(kGridMaxTracks), + numTracks(ForRows) + autoRepeatRows); + DCHECK_GE(static_cast<unsigned>(kGridMaxTracks), + numTracks(ForColumns) + autoRepeatColumns); m_autoRepeatRows = autoRepeatRows; m_autoRepeatColumns = autoRepeatColumns; }
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp index 8d111bb5..b653ab5 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
@@ -134,6 +134,11 @@ if (!documentBeingDestroyed() && parent()) parent()->dirtyLinesFromChangedChild(this); + if (LocalFrame* frame = this->frame()) { + frame->selection().layoutBlockWillBeDestroyed(*this); + frame->page()->dragCaret().layoutBlockWillBeDestroyed(*this); + } + if (TextAutosizer* textAutosizer = document().textAutosizer()) textAutosizer->destroy(this); @@ -239,8 +244,9 @@ // width or height of the block to end up being the same. We keep track of // this change so in layoutBlock, we can know to set relayoutChildren=true. m_widthAvailableToChildrenChanged |= - oldStyle && diff.needsFullLayout() && needsLayout() && - borderOrPaddingLogicalDimensionChanged(*oldStyle, newStyle, LogicalWidth); + oldStyle && needsLayout() && + (diff.needsFullLayout() || borderOrPaddingLogicalDimensionChanged( + *oldStyle, newStyle, LogicalWidth)); m_heightAvailableToChildrenChanged |= oldStyle && diff.needsFullLayout() && needsLayout() && borderOrPaddingLogicalDimensionChanged( @@ -698,7 +704,8 @@ LayoutUnit newLeft = computedValues.m_position; if (newLeft != box->logicalLeft()) layoutScope.setChildNeedsLayout(child); - } else if (hasStaticBlockPosition) { + } + if (hasStaticBlockPosition) { LogicalExtentComputedValues computedValues; box->computeLogicalHeight(computedValues); LayoutUnit newTop = computedValues.m_position; @@ -1024,7 +1031,12 @@ PaintInvalidationReason LayoutBlock::invalidatePaintIfNeeded( const PaintInvalidatorContext& context) const { - return BlockPaintInvalidator(*this, context).invalidatePaintIfNeeded(); + return BlockPaintInvalidator(*this).invalidatePaintIfNeeded(context); +} + +void LayoutBlock::clearPreviousVisualRects() { + LayoutBox::clearPreviousVisualRects(); + BlockPaintInvalidator(*this).clearPreviousVisualRects(); } void LayoutBlock::removePositionedObjects( @@ -1842,15 +1854,12 @@ editingIgnoresContent(*node()); } -bool LayoutBlock::hasCursorCaret() const { - LocalFrame* frame = this->frame(); - return frame->selection().hasCaretIn(*this); +bool LayoutBlock::shouldPaintCursorCaret() const { + return frame()->selection().shouldPaintCaret(*this); } -bool LayoutBlock::hasDragCaret() const { - LocalFrame* frame = this->frame(); - DragCaret& dragCaret = frame->page()->dragCaret(); - return dragCaret.hasCaretIn(*this); +bool LayoutBlock::shouldPaintDragCaret() const { + return frame()->page()->dragCaret().shouldPaintCaret(*this); } LayoutRect LayoutBlock::localCaretRect(InlineBox* inlineBox,
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.h b/third_party/WebKit/Source/core/layout/LayoutBlock.h index d2014ce..7b4fdaf 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlock.h +++ b/third_party/WebKit/Source/core/layout/LayoutBlock.h
@@ -486,9 +486,11 @@ bool isSelectionRoot() const; public: - bool hasCursorCaret() const; - bool hasDragCaret() const; - bool hasCaret() const { return hasCursorCaret() || hasDragCaret(); } + bool shouldPaintCursorCaret() const; + bool shouldPaintDragCaret() const; + bool shouldPaintCarets() const { + return shouldPaintCursorCaret() || shouldPaintDragCaret(); + } protected: PaintInvalidationReason invalidatePaintIfNeeded( @@ -496,6 +498,8 @@ PaintInvalidationReason invalidatePaintIfNeeded( const PaintInvalidatorContext&) const override; + void clearPreviousVisualRects() override; + private: LayoutRect localCaretRect(InlineBox*, int caretOffset,
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockTest.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockTest.cpp index a12acfb5..013e6fc 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlockTest.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBlockTest.cpp
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "core/dom/ElementTraversal.h" #include "core/layout/LayoutBlock.h" #include "core/layout/LayoutBlockFlow.h" @@ -20,4 +21,33 @@ obj->destroy(); } +TEST_F(LayoutBlockTest, WidthAvailableToChildrenChanged) { + RuntimeEnabledFeatures::setOverlayScrollbarsEnabled(false); + setBodyInnerHTML( + "<!DOCTYPE html>" + "<div id='list' style='overflow-y:auto; width:150px; height:100px'>" + " <div style='height:20px'>Item</div>" + " <div style='height:20px'>Item</div>" + " <div style='height:20px'>Item</div>" + " <div style='height:20px'>Item</div>" + " <div style='height:20px'>Item</div>" + " <div style='height:20px'>Item</div>" + "</div>"); + Element* listElement = document().getElementById("list"); + ASSERT_TRUE(listElement); + LayoutBox* listBox = toLayoutBox(listElement->layoutObject()); + Element* itemElement = ElementTraversal::firstChild(*listElement); + ASSERT_TRUE(itemElement); + ASSERT_GT(listBox->verticalScrollbarWidth(), 0); + ASSERT_EQ(itemElement->offsetWidth(), + 150 - listBox->verticalScrollbarWidth()); + + DummyExceptionStateForTesting exceptionState; + listElement->style()->setCSSText("width:150px;height:100px;", exceptionState); + ASSERT_FALSE(exceptionState.hadException()); + document().view()->updateAllLifecyclePhases(); + ASSERT_EQ(listBox->verticalScrollbarWidth(), 0); + ASSERT_EQ(itemElement->offsetWidth(), 150); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp index bc1d11d..674d218 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -312,6 +312,14 @@ updateShapeOutsideInfoAfterStyleChange(*style(), oldStyle); updateGridPositionAfterStyleChange(oldStyle); + // When we're no longer a flex item because we're now absolutely positioned, + // we need to clear the override size so we're not affected by it anymore. + // This technically covers too many cases (even when out-of-flow did not + // change) but that should be harmless. + if (isOutOfFlowPositioned() && parent() && + parent()->styleRef().isDisplayFlexibleOrGridBox()) + clearOverrideSize(); + if (LayoutMultiColumnSpannerPlaceholder* placeholder = this->spannerPlaceholder()) placeholder->layoutObjectInFlowThreadStyleDidChange(oldStyle);
diff --git a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp index 34b55a7..c31ba362d 100644 --- a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
@@ -547,13 +547,6 @@ if (needsToFulfillMinimumSize) ++repetitions; - // Clamp the number of repetitions so we don't end up with too many tracks. - if (repetitions > kGridMaxTracks) { - DCHECK_GT(autoRepeatTrackListLength, 0u); - repetitions = - (kGridMaxTracks - trackSizes.size()) / autoRepeatTrackListLength; - } - return repetitions * autoRepeatTrackListLength; } @@ -594,12 +587,35 @@ return emptyTrackIndexes; } +size_t LayoutGrid::clampAutoRepeatTracks(GridTrackSizingDirection direction, + size_t autoRepeatTracks) const { + if (!autoRepeatTracks) + return 0; + + size_t insertionPoint = direction == ForColumns + ? styleRef().gridAutoRepeatColumnsInsertionPoint() + : styleRef().gridAutoRepeatRowsInsertionPoint(); + + if (insertionPoint == 0) + return std::min<size_t>(autoRepeatTracks, kGridMaxTracks); + + if (insertionPoint >= kGridMaxTracks) + return 0; + + return std::min(autoRepeatTracks, + static_cast<size_t>(kGridMaxTracks) - insertionPoint); +} + void LayoutGrid::placeItemsOnGrid(Grid& grid, SizingOperation sizingOperation) const { size_t autoRepeatRows = computeAutoRepeatTracksCount(ForRows, sizingOperation); size_t autoRepeatColumns = computeAutoRepeatTracksCount(ForColumns, sizingOperation); + + autoRepeatRows = clampAutoRepeatTracks(ForRows, autoRepeatRows); + autoRepeatColumns = clampAutoRepeatTracks(ForColumns, autoRepeatColumns); + if (autoRepeatRows != grid.autoRepeatTracks(ForRows) || autoRepeatColumns != grid.autoRepeatTracks(ForColumns)) { grid.setNeedsItemsPlacement(true);
diff --git a/third_party/WebKit/Source/core/layout/LayoutGrid.h b/third_party/WebKit/Source/core/layout/LayoutGrid.h index 445523e..ed2b8092 100644 --- a/third_party/WebKit/Source/core/layout/LayoutGrid.h +++ b/third_party/WebKit/Source/core/layout/LayoutGrid.h
@@ -120,6 +120,8 @@ size_t computeAutoRepeatTracksCount(GridTrackSizingDirection, SizingOperation) const; + size_t clampAutoRepeatTracks(GridTrackSizingDirection, + size_t autoRepeatTracks) const; std::unique_ptr<OrderedTrackIndexSet> computeEmptyTracksForAutoRepeat( Grid&,
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp index 5948116..e913d31e1 100644 --- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -1514,13 +1514,11 @@ // needed if we have style or text affected by these properties. if (diff.textDecorationOrColorChanged() && !diff.needsPaintInvalidation()) { if (style()->hasBorder() || style()->hasOutline() || - style()->hasBackgroundRelatedColorReferencingCurrentColor() + style()->hasBackgroundRelatedColorReferencingCurrentColor() || // Skip any text nodes that do not contain text boxes. Whitespace cannot // be skipped or we will miss invalidating decorations (e.g., // underlines). - || (isText() && !isBR() && toLayoutText(this)->hasTextBoxes()) - // Caret is painted in text color. - || (isLayoutBlock() && toLayoutBlock(this)->hasCaret()) || + (isText() && !isBR() && toLayoutText(this)->hasTextBoxes()) || (isSVG() && style()->svgStyle().isFillColorCurrentColor()) || (isSVG() && style()->svgStyle().isStrokeColorCurrentColor()) || isListMarker())
diff --git a/third_party/WebKit/Source/core/layout/LayoutText.cpp b/third_party/WebKit/Source/core/layout/LayoutText.cpp index c79928f7..3f4d6a8 100644 --- a/third_party/WebKit/Source/core/layout/LayoutText.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutText.cpp
@@ -998,15 +998,21 @@ const Font& font, TextDirection textDirection, int start, - int length) { + int length, + EWordBreak breakAllOrBreakWord) { DCHECK_GT(length, 0); LazyLineBreakIterator breakIterator(layoutText->text(), style.locale()); int nextBreakable = -1; float min = std::numeric_limits<float>::max(); int end = start + length; for (int i = start; i < end;) { - breakIterator.isBreakable(i + 1, nextBreakable, LineBreakType::BreakAll); - int fragmentLength = (nextBreakable > i ? nextBreakable : length) - i; + int fragmentLength; + if (breakAllOrBreakWord == EWordBreak::BreakAllWordBreak) { + breakIterator.isBreakable(i + 1, nextBreakable, LineBreakType::BreakAll); + fragmentLength = (nextBreakable > i ? nextBreakable : length) - i; + } else { + fragmentLength = U16_LENGTH(layoutText->codepointAt(i)); + } // The correct behavior is to measure width without re-shaping, but we // reshape each fragment here because a) the current line breaker does not // support it, b) getCharacterRange() can reshape if the text is too long @@ -1094,11 +1100,16 @@ int lastWordBoundary = 0; float cachedWordTrailingSpaceWidth[2] = {0, 0}; // LTR, RTL - bool breakAll = (styleToUse.wordBreak() == BreakAllWordBreak || - styleToUse.wordBreak() == BreakWordBreak) && - styleToUse.autoWrap(); - bool keepAll = - styleToUse.wordBreak() == KeepAllWordBreak && styleToUse.autoWrap(); + EWordBreak breakAllOrBreakWord = EWordBreak::NormalWordBreak; + LineBreakType lineBreakType = LineBreakType::Normal; + if (styleToUse.autoWrap()) { + if (styleToUse.wordBreak() == BreakAllWordBreak || + styleToUse.wordBreak() == BreakWordBreak) { + breakAllOrBreakWord = styleToUse.wordBreak(); + } else if (styleToUse.wordBreak() == KeepAllWordBreak) { + lineBreakType = LineBreakType::KeepAll; + } + } Hyphenation* hyphenation = styleToUse.autoWrap() ? styleToUse.getHyphenation() : nullptr; @@ -1194,9 +1205,7 @@ continue; } - bool hasBreak = breakIterator.isBreakable( - i, nextBreakable, - keepAll ? LineBreakType::KeepAll : LineBreakType::Normal); + bool hasBreak = breakIterator.isBreakable(i, nextBreakable, lineBreakType); bool betweenWords = true; int j = i; while (c != newlineCharacter && c != spaceCharacter && @@ -1274,12 +1283,13 @@ } } - if (breakAll) { + if (breakAllOrBreakWord != EWordBreak::NormalWordBreak) { // Because sum of character widths may not be equal to the word width, // we need to measure twice; once with normal break for max width, // another with break-all for min width. - currMinWidth = minWordFragmentWidthForBreakAll( - this, styleToUse, f, textDirection, i, wordLen); + currMinWidth = + minWordFragmentWidthForBreakAll(this, styleToUse, f, textDirection, + i, wordLen, breakAllOrBreakWord); } else { currMinWidth += w; }
diff --git a/third_party/WebKit/Source/core/layout/LayoutTextControlMultiLine.cpp b/third_party/WebKit/Source/core/layout/LayoutTextControlMultiLine.cpp index 3a7bf40..38bf0e9 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTextControlMultiLine.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTextControlMultiLine.cpp
@@ -93,7 +93,7 @@ textBlockStyle->inheritFrom(startStyle); adjustInnerEditorStyle(*textBlockStyle); textBlockStyle->setDisplay(EDisplay::Block); - textBlockStyle->setUnique(); + textBlockStyle->setUnique(true); return textBlockStyle.release(); }
diff --git a/third_party/WebKit/Source/core/layout/LayoutTextControlSingleLine.cpp b/third_party/WebKit/Source/core/layout/LayoutTextControlSingleLine.cpp index f0ea860..2580d9b83 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTextControlSingleLine.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTextControlSingleLine.cpp
@@ -327,7 +327,7 @@ textBlockStyle->setLineHeight(ComputedStyle::initialLineHeight()); textBlockStyle->setDisplay(EDisplay::Block); - textBlockStyle->setUnique(); + textBlockStyle->setUnique(true); if (inputElement()->shouldRevealPassword()) textBlockStyle->setTextSecurity(TSNONE);
diff --git a/third_party/WebKit/Source/core/layout/README.md b/third_party/WebKit/Source/core/layout/README.md index 0100895cc..b8939ac 100644 --- a/third_party/WebKit/Source/core/layout/README.md +++ b/third_party/WebKit/Source/core/layout/README.md
@@ -1,7 +1,7 @@ -# `Source/core/layout` +# Blink Layout -This directory contains implementation of layout objects. It covers the -following document lifecycle states: +The `Source/core/layout` directory contains the implementation of layout objects. +It covers the following document lifecycle states: * LayoutSubtreeChange (`InLayoutSubtreeChange` and `LayoutSubtreeChangeClean`) * PreLayout (`InPreLayout`) @@ -11,7 +11,10 @@ Note that a new Blink layout system is under development. See the [LayoutNG design document](https://docs.google.com/document/d/1uxbDh4uONFQOiGuiumlJBLGgO4KDWB8ZEkp7Rd47fw4/preview). -## Overflow and scrolling +The layout code is maintained by the +[layout team](http://dev.chromium.org/blink/layout-team). + +## Scroll origin vs. offset vs. position When a LayoutBox has scrollable overflow, it is associated with a PaintLayerScrollableArea. PaintLayerScrollableArea uses a "scroll origin" to represent the location of the top/left @@ -61,7 +64,7 @@ | |/| | | |/| | |__________|/|__________| - + overflow rect |<--------------------->| @@ -79,7 +82,7 @@ vertical-rl | | |/| | | |/| |____________|__________|/| - + overflow rect |<--------------------->| @@ -284,6 +287,11 @@ [Scrolling in Blink](https://docs.google.com/presentation/d/1pwx0qBW4wSmYAOJxq2gb3SMvSTCHz2L2TFx_bjsvm8E/preview) is a good overview. +*Root layer scrolling* is an ongoing refactoring of Blink's scrolling +architecture, which makes the root `PaintLayer` responsible for the scrolling +that was previously done by `FrameView`. For more details, see: +[Root Layer Scrolling](https://bit.ly/root-layer-scrolling). + ## Glossaries Here we provide a brief overview of key terms relevant to box flow, inline flow,
diff --git a/third_party/WebKit/Source/core/layout/TextAutosizer.cpp b/third_party/WebKit/Source/core/layout/TextAutosizer.cpp index af61f4e..4b838e0 100644 --- a/third_party/WebKit/Source/core/layout/TextAutosizer.cpp +++ b/third_party/WebKit/Source/core/layout/TextAutosizer.cpp
@@ -1163,7 +1163,7 @@ // We need to clone the layoutObject style to avoid breaking style sharing. RefPtr<ComputedStyle> style = ComputedStyle::clone(currentStyle); style->setTextAutosizingMultiplier(multiplier); - style->setUnique(); + style->setUnique(true); switch (relayoutBehavior) { case AlreadyInLayout:
diff --git a/third_party/WebKit/Source/core/layout/VisualRectMappingTest.cpp b/third_party/WebKit/Source/core/layout/VisualRectMappingTest.cpp index 0ff8052..1f0486a 100644 --- a/third_party/WebKit/Source/core/layout/VisualRectMappingTest.cpp +++ b/third_party/WebKit/Source/core/layout/VisualRectMappingTest.cpp
@@ -127,8 +127,8 @@ // This case involves clipping: frame height is 50, y-coordinate of result // rect is 13, so height should be clipped to (50 - 13) == 37. - childDocument().view()->setScrollOffset(ScrollOffset(0, 47), - ProgrammaticScroll); + childDocument().view()->layoutViewportScrollableArea()->setScrollOffset( + ScrollOffset(0, 47), ProgrammaticScroll); document().view()->updateAllLifecyclePhases(); LayoutRect originalRect(4, 60, 20, 80); @@ -197,8 +197,8 @@ // This part is copied from the LayoutView test, just to ensure that the // mapped rect is valid before display:none is set on the iframe. - childDocument().view()->setScrollOffset(ScrollOffset(0, 47), - ProgrammaticScroll); + childDocument().view()->layoutViewportScrollableArea()->setScrollOffset( + ScrollOffset(0, 47), ProgrammaticScroll); document().view()->updateAllLifecyclePhases(); LayoutRect originalRect(4, 60, 20, 80);
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutBlockItem.h b/third_party/WebKit/Source/core/layout/api/LayoutBlockItem.h index 79af5ff..d818beb1 100644 --- a/third_party/WebKit/Source/core/layout/api/LayoutBlockItem.h +++ b/third_party/WebKit/Source/core/layout/api/LayoutBlockItem.h
@@ -24,6 +24,10 @@ LayoutBlockItem() {} + void flipForWritingMode(LayoutRect& rect) const { + toBlock()->flipForWritingMode(rect); + } + bool recalcOverflowAfterStyleChange() { return toBlock()->recalcOverflowAfterStyleChange(); }
diff --git a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp b/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp index a8da568..ab1872a 100644 --- a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp +++ b/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp
@@ -719,8 +719,14 @@ // similar between platforms (unless we explicitly request dumping from the // root. GraphicsLayer* rootLayer = m_rootContentLayer.get(); - if (flags & LayerTreeIncludesRootLayer) - rootLayer = rootGraphicsLayer(); + if (flags & LayerTreeIncludesRootLayer) { + if (m_layoutView.frame()->isMainFrame()) { + while (rootLayer->parent()) + rootLayer = rootLayer->parent(); + } else { + rootLayer = rootGraphicsLayer(); + } + } return rootLayer->layerTreeAsJSON(flags); }
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc index ea90c1ae..c58908fa 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
@@ -25,12 +25,29 @@ namespace blink { namespace { +// Whether child's constraint space should shrink to its intrinsic width. +// This is needed for buttons, select, input, floats and orthogonal children. +// See LayoutBox::sizesLogicalWidthToFitContent for the rationale behind this. +bool ShouldShrinkToFit(const NGConstraintSpace& parent_space, + const ComputedStyle& child_style) { + NGWritingMode child_writing_mode = + FromPlatformWritingMode(child_style.getWritingMode()); + // Whether the child and the containing block are parallel to each other. + // Example: vertical-rl and vertical-lr + bool is_in_parallel_flow = + (parent_space.WritingMode() == kHorizontalTopBottom) == + (child_writing_mode == kHorizontalTopBottom); + + return child_style.display() == EDisplay::InlineBlock || + child_style.isFloating() || !is_in_parallel_flow; +} + // Updates the fragment's BFC offset if it's not already set. void UpdateFragmentBfcOffset(const NGLogicalOffset& offset, const NGConstraintSpace& space, NGFragmentBuilder* builder) { NGLogicalOffset fragment_offset = - space.IsNewFormattingContext() ? NGLogicalOffset() : offset; + space.IsNewFormattingContext() ? space.BfcOffset() : offset; if (!builder->BfcOffset()) builder->SetBfcOffset(fragment_offset); } @@ -379,7 +396,8 @@ // Margins collapsing: // Do not collapse margins between parent and its child if there is // border/padding between them. - if (border_and_padding_.block_start) { + if (border_and_padding_.block_start || + ConstraintSpace().IsNewFormattingContext()) { curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); builder_->SetBfcOffset(curr_bfc_offset_); curr_margin_strut_ = NGMarginStrut(); @@ -702,30 +720,27 @@ NGConstraintSpace* NGBlockLayoutAlgorithm::CreateConstraintSpaceForCurrentChild() { - // TODO(layout-ng): Orthogonal children should also shrink to fit (in *their* - // inline axis) DCHECK(current_child_); if (current_child_->Type() == NGLayoutInputNode::kLegacyInline) { // TODO(kojii): Setup space_builder_ appropriately for inline child. return space_builder_->ToConstraintSpace(); + // Calculate margins in parent's writing mode. } + curr_child_margins_ = CalculateMargins(*space_builder_->ToConstraintSpace(), + CurrentChildStyle()); const ComputedStyle& current_child_style = CurrentChildStyle(); - bool shrink_to_fit = current_child_style.display() == EDisplay::InlineBlock || - current_child_style.isFloating(); bool is_new_bfc = IsNewFormattingContextForInFlowBlockLevelChild( ConstraintSpace(), current_child_style); space_builder_->SetIsNewFormattingContext(is_new_bfc) - .SetIsShrinkToFit(shrink_to_fit) + .SetIsShrinkToFit( + ShouldShrinkToFit(ConstraintSpace(), CurrentChildStyle())) .SetWritingMode( FromPlatformWritingMode(current_child_style.getWritingMode())) .SetTextDirection(current_child_style.direction()); LayoutUnit space_available = SpaceAvailableForCurrentChild(); space_builder_->SetFragmentainerSpaceAvailable(space_available); - curr_child_margins_ = CalculateMargins(*space_builder_->ToConstraintSpace(), - current_child_style); - // Clearance : // - Collapse margins // - Update curr_bfc_offset and parent BFC offset if needed.
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h index 6b48b4ac..a9fe01b 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h +++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
@@ -101,7 +101,6 @@ // Calculates offset for the provided fragment which is relative to the // fragment's parent. NGLogicalOffset CalculateRelativeOffset(const NGBoxFragment& fragment); - NGLogicalOffset GetChildSpaceOffset() const { return NGLogicalOffset(border_and_padding_.inline_start, content_size_); }
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc index 9b15000..25788e2 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
@@ -544,50 +544,80 @@ // Verifies that margins of 2 adjoining blocks with different writing modes // get collapsed. -// -// Test case's HTML representation: -// <div style="writing-mode: vertical-lr;"> -// <div style="margin-right: 60px; width: 60px;">vertical</div> -// <div style="margin-left: 100px; writing-mode: horizontal-tb;"> -// horizontal -// </div> -// </div> -// TODO(glebl): fix writing modes support after new margin collapsing/floats -// algorithm is checked in. -TEST_F(NGBlockLayoutAlgorithmTest, DISABLED_CollapsingMarginsCase5) { - const int kVerticalDivMarginRight = 60; - const int kVerticalDivWidth = 50; - const int kHorizontalDivMarginLeft = 100; +TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsCase5) { + setBodyInnerHTML( + "<style>" + // TODO(glebl): Remove the fixed height + // Fix this once min/max algorithm handles orthogonal children. + " body {" + " height: 500px;" + " }" + " #container {" + " margin-top: 10px;" + // TODO(glebl): Remove the fixed height + // Fix this once min/max algorithm handles orthogonal children. + " width: 500px;" + " writing-mode: vertical-lr;" + " }" + " #vertical {" + " margin-right: 90px;" + " background-color: red;" + " height: 70px;" + " width: 30px;" + " }" + " #horizontal {" + " background-color: blue;" + " margin-left: 100px;" + " writing-mode: horizontal-tb;" + " height: 60px;" + " width: 30px;" + " }" + "</style>" + "<div id='container'>" + " <div id='vertical'></div>" + " <div id='horizontal'></div>" + "</div>"); + RefPtr<NGPhysicalBoxFragment> fragment; + std::tie(fragment, std::ignore) = RunBlockLayoutAlgorithmForElement( + document().getElementsByTagName("html")->item(0)); - style_->setWidth(Length(500, Fixed)); - style_->setHeight(Length(500, Fixed)); - style_->setWritingMode(WritingMode::kVerticalLr); + // body + auto* body_fragment = toNGPhysicalBoxFragment(fragment->Children()[0].get()); + // 10 = std::max(body's margin 8, container's margin top) + int body_top_offset = 10; + EXPECT_THAT(body_fragment->TopOffset(), LayoutUnit(body_top_offset)); + int body_left_offset = 8; + EXPECT_THAT(body_fragment->LeftOffset(), LayoutUnit(body_left_offset)); + // height = 70. std::max(vertical height's 70, horizontal's height's 60) + // TODO(glebl): Should be 70! Fix this once min/max algorithm handles + // orthogonal children. + int body_fragment_block_size = 500; + ASSERT_EQ( + NGPhysicalSize(LayoutUnit(784), LayoutUnit(body_fragment_block_size)), + body_fragment->Size()); + ASSERT_EQ(1UL, body_fragment->Children().size()); - // Vertical DIV - RefPtr<ComputedStyle> vertical_style = ComputedStyle::create(); - vertical_style->setMarginRight(Length(kVerticalDivMarginRight, Fixed)); - vertical_style->setWidth(Length(kVerticalDivWidth, Fixed)); - NGBlockNode* vertical_div = new NGBlockNode(vertical_style.get()); + // container + auto* container_fragment = + toNGPhysicalBoxFragment(body_fragment->Children()[0].get()); + // Container's margins are collapsed with body's fragment. + EXPECT_THAT(container_fragment->TopOffset(), LayoutUnit()); + EXPECT_THAT(container_fragment->LeftOffset(), LayoutUnit()); + ASSERT_EQ(2UL, container_fragment->Children().size()); - // Horizontal DIV - RefPtr<ComputedStyle> horizontal_style = ComputedStyle::create(); - horizontal_style->setMarginLeft(Length(kHorizontalDivMarginLeft, Fixed)); - horizontal_style->setWritingMode(WritingMode::kHorizontalTb); - NGBlockNode* horizontal_div = new NGBlockNode(horizontal_style.get()); + // vertical + auto* vertical_fragment = + toNGPhysicalBoxFragment(container_fragment->Children()[0].get()); + EXPECT_THAT(vertical_fragment->TopOffset(), LayoutUnit()); + EXPECT_THAT(vertical_fragment->LeftOffset(), LayoutUnit()); - vertical_div->SetNextSibling(horizontal_div); - - auto* space = - ConstructConstraintSpace(kVerticalLeftRight, TextDirection::kLtr, - NGLogicalSize(LayoutUnit(500), LayoutUnit(500))); - RefPtr<NGPhysicalBoxFragment> frag = - RunBlockLayoutAlgorithm(space, vertical_div); - - ASSERT_EQ(frag->Children().size(), 2UL); - const NGPhysicalFragment* child = frag->Children()[1].get(); - // Horizontal div - EXPECT_EQ(0, child->TopOffset()); - EXPECT_EQ(kVerticalDivWidth + kHorizontalDivMarginLeft, child->LeftOffset()); + // horizontal + auto* horizontal_fragment = + toNGPhysicalBoxFragment(container_fragment->Children()[1].get()); + EXPECT_THAT(horizontal_fragment->TopOffset(), LayoutUnit()); + // 130 = vertical's width 30 + + // std::max(vertical's margin right 90, horizontal's margin-left 100) + EXPECT_THAT(horizontal_fragment->LeftOffset(), LayoutUnit(130)); } // Verifies that the margin strut of a child with a different writing mode does @@ -603,7 +633,9 @@ // <div id="div2">vertical</div> // </div> // <div id="div3"></div> -TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsCase6) { +// TODO(glebl): Disabled for now. Follow-up with kojii@ on +// https://software.hixie.ch/utilities/js/live-dom-viewer/?saved=4844 +TEST_F(NGBlockLayoutAlgorithmTest, DISABLED_CollapsingMarginsCase6) { const int kHeight = 60; const int kWidth = 10; const int kMarginBottom = 10;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_node.h b/third_party/WebKit/Source/core/layout/ng/ng_block_node.h index 7f42162..0306826f 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_block_node.h +++ b/third_party/WebKit/Source/core/layout/ng/ng_block_node.h
@@ -6,6 +6,7 @@ #define NGBlockNode_h #include "core/CoreExport.h" +#include "core/layout/LayoutBox.h" #include "core/layout/ng/ng_layout_input_node.h" #include "core/layout/ng/ng_physical_box_fragment.h" #include "platform/heap/Handle.h" @@ -13,7 +14,6 @@ namespace blink { class ComputedStyle; -class LayoutBox; class LayoutObject; class NGBreakToken; class NGConstraintSpace; @@ -59,6 +59,9 @@ return fragment_ && !fragment_->BreakToken(); } + // Used for debugging purposes only. + const LayoutBox* LegacyLayoutBox() const { return layout_box_; } + DECLARE_VIRTUAL_TRACE(); // Runs layout on layout_box_ and creates a fragment for the resulting
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_constraint_space.h b/third_party/WebKit/Source/core/layout/ng/ng_constraint_space.h index 35622c7f..b3edfc2 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_constraint_space.h +++ b/third_party/WebKit/Source/core/layout/ng/ng_constraint_space.h
@@ -110,6 +110,7 @@ NGMarginStrut MarginStrut() const { return margin_strut_; } + // TODO(glebl): Rename to Offset() or AbsoluteOffset(). NGLogicalOffset BfcOffset() const { return bfc_offset_; } DEFINE_INLINE_VIRTUAL_TRACE() {}
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_constraint_space_builder.cc b/third_party/WebKit/Source/core/layout/ng/ng_constraint_space_builder.cc index e35cee16..141a3d5 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_constraint_space_builder.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_constraint_space_builder.cc
@@ -14,7 +14,7 @@ percentage_resolution_size_(parent_space->PercentageResolutionSize()), fragmentainer_space_available_(NGSizeIndefinite), writing_mode_(parent_space->WritingMode()), - parent_writing_mode_(writing_mode_), + parent_writing_mode_(parent_space->WritingMode()), is_fixed_size_inline_(false), is_fixed_size_block_(false), is_shrink_to_fit_(false), @@ -117,18 +117,11 @@ } NGConstraintSpace* NGConstraintSpaceBuilder::ToConstraintSpace() { - // Exclusions do not pass the formatting context boundary. - std::shared_ptr<NGExclusions> exclusions( - is_new_fc_ ? std::make_shared<NGExclusions>() : exclusions_); - // Whether the child and the containing block are parallel to each other. // Example: vertical-rl and vertical-lr bool is_in_parallel_flow = (parent_writing_mode_ == kHorizontalTopBottom) == (writing_mode_ == kHorizontalTopBottom); - NGMarginStrut margin_strut = is_new_fc_ ? NGMarginStrut() : margin_strut_; - NGLogicalOffset bfc_offset = is_new_fc_ ? NGLogicalOffset() : bfc_offset_; - if (is_in_parallel_flow) { return new NGConstraintSpace( static_cast<NGWritingMode>(writing_mode_), @@ -141,7 +134,7 @@ is_inline_direction_triggers_scrollbar_, is_block_direction_triggers_scrollbar_, static_cast<NGFragmentationType>(fragmentation_type_), is_new_fc_, - margin_strut, bfc_offset, exclusions); + margin_strut_, bfc_offset_, exclusions_); } return new NGConstraintSpace( @@ -155,7 +148,7 @@ is_block_direction_triggers_scrollbar_, is_inline_direction_triggers_scrollbar_, static_cast<NGFragmentationType>(fragmentation_type_), is_new_fc_, - margin_strut, bfc_offset, exclusions); + margin_strut_, bfc_offset_, exclusions_); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.cpp index 525258e..fe3dd926 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.cpp
@@ -230,8 +230,7 @@ LayoutObject* layoutObject = pendingClient->layoutObject(); if (!layoutObject) continue; - DCHECK(layoutObject->isSVG() && (resourceType() != FilterResourceType || - !layoutObject->isSVGRoot())); + DCHECK(layoutObject->isSVG()); StyleDifference diff; diff.setNeedsFullLayout();
diff --git a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp index 613a0e43..d4e6c19 100644 --- a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp +++ b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
@@ -440,7 +440,7 @@ m_request.setURL(blockedURL); m_redirectChain.pop_back(); appendRedirect(blockedURL); - m_response = ResourceResponse(blockedURL, "text/html", 0, nullAtom, String()); + m_response = ResourceResponse(blockedURL, "text/html", 0, nullAtom); finishedLoading(monotonicallyIncreasingTime()); return; @@ -709,8 +709,7 @@ if (m_request.url().isEmpty() && !frameLoader().stateMachine()->creatingInitialEmptyDocument()) m_request.setURL(blankURL()); - m_response = - ResourceResponse(m_request.url(), "text/html", 0, nullAtom, String()); + m_response = ResourceResponse(m_request.url(), "text/html", 0, nullAtom); finishedLoading(monotonicallyIncreasingTime()); return true; }
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.h b/third_party/WebKit/Source/core/loader/EmptyClients.h index 09b2f8d..66543a6 100644 --- a/third_party/WebKit/Source/core/loader/EmptyClients.h +++ b/third_party/WebKit/Source/core/loader/EmptyClients.h
@@ -260,7 +260,7 @@ void dispatchDidHandleOnloadEvents() override {} void dispatchDidReceiveServerRedirectForProvisionalLoad() override {} void dispatchWillCommitProvisionalLoad() override {} - void dispatchDidStartProvisionalLoad() override {} + void dispatchDidStartProvisionalLoad(DocumentLoader*) override {} void dispatchDidReceiveTitle(const String&) override {} void dispatchDidChangeIcons(IconType) override {} void dispatchDidCommitLoad(HistoryItem*, HistoryCommitType) override {}
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp index 7eee012..607cefdf 100644 --- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp +++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -571,7 +571,7 @@ ResourceRequest& request, Resource::Type type, const AtomicString& fetchInitiatorName, - bool forPreload) { + V8ActivityLoggingPolicy loggingPolicy) { TRACE_EVENT_ASYNC_BEGIN1( "blink.net", "Resource", identifier, "data", loadResourceTraceData(identifier, request.url(), request.priority())); @@ -586,7 +586,7 @@ } else { m_documentLoader->applicationCacheHost()->willStartLoadingResource(request); } - if (!forPreload) { + if (loggingPolicy == V8ActivityLoggingPolicy::Log) { V8DOMActivityLogger* activityLogger = nullptr; if (fetchInitiatorName == FetchInitiatorTypeNames::xmlhttprequest) { activityLogger = V8DOMActivityLogger::currentActivityLogger(); @@ -652,12 +652,13 @@ const ResourceRequest& resourceRequest, const KURL& url, const ResourceLoaderOptions& options, - bool forPreload, + SecurityViolationReportingPolicy reportingPolicy, FetchRequest::OriginRestriction originRestriction) const { ResourceRequestBlockedReason blockedReason = - canRequestInternal(type, resourceRequest, url, options, forPreload, + canRequestInternal(type, resourceRequest, url, options, reportingPolicy, originRestriction, resourceRequest.redirectStatus()); - if (blockedReason != ResourceRequestBlockedReason::None && !forPreload) { + if (blockedReason != ResourceRequestBlockedReason::None && + reportingPolicy == SecurityViolationReportingPolicy::Report) { InspectorInstrumentation::didBlockRequest( frame(), resourceRequest, masterDocumentLoader(), options.initiatorInfo, blockedReason); @@ -671,7 +672,8 @@ const KURL& url, const ResourceLoaderOptions& options) const { ResourceRequestBlockedReason blockedReason = - canRequestInternal(type, resourceRequest, url, options, false, + canRequestInternal(type, resourceRequest, url, options, + SecurityViolationReportingPolicy::Report, FetchRequest::UseDefaultOriginRestrictionForType, RedirectStatus::FollowedRedirect); if (blockedReason != ResourceRequestBlockedReason::None) { @@ -687,7 +689,7 @@ const ResourceRequest& resourceRequest, const KURL& url, const ResourceLoaderOptions& options, - bool forPreload, + SecurityViolationReportingPolicy reportingPolicy, FetchRequest::OriginRestriction originRestriction, ResourceRequest::RedirectStatus redirectStatus) const { if (InspectorInstrumentation::shouldBlockRequest(frame(), resourceRequest)) @@ -699,7 +701,7 @@ if (originRestriction != FetchRequest::NoOriginRestriction && securityOrigin && !securityOrigin->canDisplay(url)) { - if (!forPreload) + if (reportingPolicy == SecurityViolationReportingPolicy::Report) FrameLoader::reportLocalLoadFailed(frame(), url.elidedString()); RESOURCE_LOADING_DVLOG(1) << "ResourceFetcher::requestResource URL was not " "allowed by SecurityOrigin::canDisplay"; @@ -746,11 +748,10 @@ frame()->script().shouldBypassMainWorldCSP() || options.contentSecurityPolicyOption == DoNotCheckContentSecurityPolicy; - // Don't send CSP messages for preloads, we might never actually display those - // items. ContentSecurityPolicy::ReportingStatus cspReporting = - forPreload ? ContentSecurityPolicy::SuppressReport - : ContentSecurityPolicy::SendReport; + (reportingPolicy == SecurityViolationReportingPolicy::SuppressReporting) + ? ContentSecurityPolicy::SuppressReport + : ContentSecurityPolicy::SendReport; if (m_document) { DCHECK(m_document->contentSecurityPolicy()); @@ -807,8 +808,9 @@ // mixed content with a CSP policy, they don't get a warning. They'll still // get a warning in the console about CSP blocking the load. MixedContentChecker::ReportingStatus mixedContentReporting = - forPreload ? MixedContentChecker::SuppressReport - : MixedContentChecker::SendReport; + (reportingPolicy == SecurityViolationReportingPolicy::SuppressReporting) + ? MixedContentChecker::SuppressReport + : MixedContentChecker::SendReport; if (MixedContentChecker::shouldBlockFetch(frame(), resourceRequest, url, mixedContentReporting)) return ResourceRequestBlockedReason::MixedContent; @@ -817,10 +819,26 @@ // proceed. DocumentLoader* documentLoader = masterDocumentLoader(); if (documentLoader && documentLoader->subresourceFilter() && - type != Resource::MainResource && type != Resource::ImportResource && - !documentLoader->subresourceFilter()->allowLoad( - url, resourceRequest.requestContext())) - return ResourceRequestBlockedReason::SubresourceFilter; + type != Resource::MainResource && type != Resource::ImportResource) { + WebDocumentSubresourceFilter::LoadPolicy loadPolicy = + documentLoader->subresourceFilter()->getLoadPolicy( + url, resourceRequest.requestContext()); + if (reportingPolicy == SecurityViolationReportingPolicy::Report) { + switch (loadPolicy) { + case WebDocumentSubresourceFilter::Allow: + break; + case WebDocumentSubresourceFilter::Disallow: + documentLoader->subresourceFilter()->reportDisallowedLoad(); + // fall through + case WebDocumentSubresourceFilter::WouldDisallow: + documentLoader->didObserveLoadingBehavior( + WebLoadingBehaviorSubresourceFilterMatch); + break; + } + } + if (loadPolicy == WebDocumentSubresourceFilter::Disallow) + return ResourceRequestBlockedReason::SubresourceFilter; + } return ResourceRequestBlockedReason::None; }
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.h b/third_party/WebKit/Source/core/loader/FrameFetchContext.h index b3fbffb8..bcd82eb8 100644 --- a/third_party/WebKit/Source/core/loader/FrameFetchContext.h +++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.h
@@ -118,7 +118,7 @@ ResourceRequest&, Resource::Type, const AtomicString& fetchInitiatorName, - bool forPreload) override; + V8ActivityLoggingPolicy) override; void didLoadResource(Resource*) override; void addResourceTiming(const ResourceTimingInfo&) override; @@ -128,7 +128,7 @@ const ResourceRequest&, const KURL&, const ResourceLoaderOptions&, - bool forPreload, + SecurityViolationReportingPolicy, FetchRequest::OriginRestriction) const override; ResourceRequestBlockedReason allowResponse( Resource::Type, @@ -185,7 +185,7 @@ const ResourceRequest&, const KURL&, const ResourceLoaderOptions&, - bool forPreload, + SecurityViolationReportingPolicy, FetchRequest::OriginRestriction, ResourceRequest::RedirectStatus) const;
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp index 61736253..3f78de4 100644 --- a/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp +++ b/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp
@@ -30,6 +30,7 @@ #include "core/loader/FrameFetchContext.h" +#include <memory> #include "core/dom/Document.h" #include "core/frame/FrameHost.h" #include "core/frame/FrameOwner.h" @@ -48,10 +49,10 @@ #include "platform/weborigin/KURL.h" #include "public/platform/WebAddressSpace.h" #include "public/platform/WebCachePolicy.h" +#include "public/platform/WebDocumentSubresourceFilter.h" #include "public/platform/WebInsecureRequestPolicy.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -#include <memory> namespace blink { @@ -82,6 +83,23 @@ void(const ResourceRequest&, const ResourceResponse&)); }; +class FixedPolicySubresourceFilter : public WebDocumentSubresourceFilter { + public: + FixedPolicySubresourceFilter(LoadPolicy policy, int* filteredLoadCounter) + : m_policy(policy), m_filteredLoadCounter(filteredLoadCounter) {} + + LoadPolicy getLoadPolicy(const WebURL& resourceUrl, + WebURLRequest::RequestContext) override { + return m_policy; + } + + void reportDisallowedLoad() override { ++*m_filteredLoadCounter; } + + private: + const LoadPolicy m_policy; + int* m_filteredLoadCounter; +}; + class FrameFetchContextTest : public ::testing::Test { protected: void SetUp() override { @@ -126,6 +144,49 @@ Persistent<DummyFrameOwner> owner; }; +class FrameFetchContextSubresourceFilterTest : public FrameFetchContextTest { + protected: + void SetUp() override { + FrameFetchContextTest::SetUp(); + m_filteredLoadCallbackCounter = 0; + } + + void TearDown() override { + document->loader()->setSubresourceFilter(nullptr); + FrameFetchContextTest::TearDown(); + } + + int getFilteredLoadCallCount() const { return m_filteredLoadCallbackCounter; } + + void setFilterPolicy(WebDocumentSubresourceFilter::LoadPolicy policy) { + document->loader()->setSubresourceFilter( + WTF::makeUnique<FixedPolicySubresourceFilter>( + policy, &m_filteredLoadCallbackCounter)); + } + + ResourceRequestBlockedReason canRequest() { + return canRequestInternal( + FetchContext::SecurityViolationReportingPolicy::Report); + } + + ResourceRequestBlockedReason canRequestPreload() { + return canRequestInternal( + FetchContext::SecurityViolationReportingPolicy::SuppressReporting); + } + + private: + ResourceRequestBlockedReason canRequestInternal( + FetchContext::SecurityViolationReportingPolicy reportingPolicy) { + KURL inputURL(ParsedURLString, "http://example.com/"); + ResourceRequest resourceRequest(inputURL); + return fetchContext->canRequest( + Resource::Image, resourceRequest, inputURL, ResourceLoaderOptions(), + reportingPolicy, FetchRequest::UseDefaultOriginRestrictionForType); + } + + int m_filteredLoadCallbackCounter; +}; + // This test class sets up a mock frame loader client. class FrameFetchContextMockedFrameLoaderClientTest : public FrameFetchContextTest { @@ -809,4 +870,41 @@ } } +TEST_F(FrameFetchContextSubresourceFilterTest, Filter) { + setFilterPolicy(WebDocumentSubresourceFilter::Disallow); + + EXPECT_EQ(ResourceRequestBlockedReason::SubresourceFilter, canRequest()); + EXPECT_EQ(1, getFilteredLoadCallCount()); + + EXPECT_EQ(ResourceRequestBlockedReason::SubresourceFilter, canRequest()); + EXPECT_EQ(2, getFilteredLoadCallCount()); + + EXPECT_EQ(ResourceRequestBlockedReason::SubresourceFilter, + canRequestPreload()); + EXPECT_EQ(2, getFilteredLoadCallCount()); + + EXPECT_EQ(ResourceRequestBlockedReason::SubresourceFilter, canRequest()); + EXPECT_EQ(3, getFilteredLoadCallCount()); +} + +TEST_F(FrameFetchContextSubresourceFilterTest, Allow) { + setFilterPolicy(WebDocumentSubresourceFilter::Allow); + + EXPECT_EQ(ResourceRequestBlockedReason::None, canRequest()); + EXPECT_EQ(0, getFilteredLoadCallCount()); + + EXPECT_EQ(ResourceRequestBlockedReason::None, canRequestPreload()); + EXPECT_EQ(0, getFilteredLoadCallCount()); +} + +TEST_F(FrameFetchContextSubresourceFilterTest, WouldDisallow) { + setFilterPolicy(WebDocumentSubresourceFilter::WouldDisallow); + + EXPECT_EQ(ResourceRequestBlockedReason::None, canRequest()); + EXPECT_EQ(0, getFilteredLoadCallCount()); + + EXPECT_EQ(ResourceRequestBlockedReason::None, canRequestPreload()); + EXPECT_EQ(0, getFilteredLoadCallCount()); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/third_party/WebKit/Source/core/loader/FrameLoader.cpp index 66aa1f2..f773065 100644 --- a/third_party/WebKit/Source/core/loader/FrameLoader.cpp +++ b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
@@ -1730,26 +1730,44 @@ if (!checkLoadCanStart(frameLoadRequest, type, navigationPolicy, navigationType)) { - // PlzNavigate: if the navigation is a commit of a client-handled - // navigation, record that there is no longer a navigation handled by the - // client. - if (m_isNavigationHandledByClient && - !frameLoadRequest.resourceRequest().checkForBrowserSideNavigation()) { - m_isNavigationHandledByClient = false; + if (m_isNavigationHandledByClient) { + // PlzNavigate: if the navigation is a commit of a client-handled + // navigation, record that there is no longer a navigation handled by the + // client. + if (!frameLoadRequest.resourceRequest().checkForBrowserSideNavigation()) { + m_isNavigationHandledByClient = false; + } else { + DocumentLoader* loader = createDocumentLoader( + resourceRequest, frameLoadRequest, type, navigationType); + // PlzNavigate: If the navigation is handled by the client, then the + // didFinishDocumentLoad() event occurs before the + // didStartProvisionalLoad() notification which occurs after the + // navigation + // is committed. This causes a number of layout tests to fail. We + // workaround this by invoking the didStartProvisionalLoad() + // notification + // here. Consumers of the didStartProvisionalLoad() notification rely on + // the provisional loader and save navigation state in it. We want to + // avoid + // this dependency on the provisional loader. For now we create a + // temporary + // loader and pass it to the didStartProvisionalLoad() function. + // TODO(ananta) + // We should get rid of the dependency on the DocumentLoader in + // consumers + // of + // the didStartProvisionalLoad() notification. + client()->dispatchDidStartProvisionalLoad(loader); + DCHECK(loader); + loader->setSentDidFinishLoad(); + loader->detachFromFrame(); + } } return; } - m_provisionalDocumentLoader = client()->createDocumentLoader( - m_frame, resourceRequest, - frameLoadRequest.substituteData().isValid() - ? frameLoadRequest.substituteData() - : defaultSubstituteDataForURL(resourceRequest.url()), - frameLoadRequest.clientRedirect()); - m_provisionalDocumentLoader->setLoadType(type); - m_provisionalDocumentLoader->setNavigationType(navigationType); - m_provisionalDocumentLoader->setReplacesCurrentHistoryItem( - type == FrameLoadTypeReplaceCurrentItem); + m_provisionalDocumentLoader = createDocumentLoader( + resourceRequest, frameLoadRequest, type, navigationType); // PlzNavigate: We need to ensure that script initiated navigations are // honored. @@ -1771,8 +1789,12 @@ m_provisionalDocumentLoader->appendRedirect( m_provisionalDocumentLoader->getRequest().url()); - client()->dispatchDidStartProvisionalLoad(); + // TODO(ananta) + // We should get rid of the dependency on the DocumentLoader in consumers of + // the didStartProvisionalLoad() notification. + client()->dispatchDidStartProvisionalLoad(m_provisionalDocumentLoader); DCHECK(m_provisionalDocumentLoader); + m_provisionalDocumentLoader->startLoadingMainResource(); takeObjectSnapshot(); @@ -1963,4 +1985,22 @@ toTracedValue()); } +DocumentLoader* FrameLoader::createDocumentLoader( + const ResourceRequest& request, + const FrameLoadRequest& frameLoadRequest, + FrameLoadType loadType, + NavigationType navigationType) { + DocumentLoader* loader = client()->createDocumentLoader( + m_frame, request, frameLoadRequest.substituteData().isValid() + ? frameLoadRequest.substituteData() + : defaultSubstituteDataForURL(request.url()), + frameLoadRequest.clientRedirect()); + + loader->setLoadType(loadType); + loader->setNavigationType(navigationType); + loader->setReplacesCurrentHistoryItem(loadType == + FrameLoadTypeReplaceCurrentItem); + return loader; +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.h b/third_party/WebKit/Source/core/loader/FrameLoader.h index 6c85d34..dc55504 100644 --- a/third_party/WebKit/Source/core/loader/FrameLoader.h +++ b/third_party/WebKit/Source/core/loader/FrameLoader.h
@@ -267,6 +267,11 @@ std::unique_ptr<TracedValue> toTracedValue() const; void takeObjectSnapshot() const; + DocumentLoader* createDocumentLoader(const ResourceRequest&, + const FrameLoadRequest&, + FrameLoadType, + NavigationType); + Member<LocalFrame> m_frame; AtomicString m_requiredCSP;
diff --git a/third_party/WebKit/Source/core/loader/FrameLoaderClient.h b/third_party/WebKit/Source/core/loader/FrameLoaderClient.h index a22c31d..c51382646 100644 --- a/third_party/WebKit/Source/core/loader/FrameLoaderClient.h +++ b/third_party/WebKit/Source/core/loader/FrameLoaderClient.h
@@ -102,7 +102,7 @@ HistoryCommitType, bool contentInitiated) {} virtual void dispatchWillCommitProvisionalLoad() = 0; - virtual void dispatchDidStartProvisionalLoad() = 0; + virtual void dispatchDidStartProvisionalLoad(DocumentLoader*) = 0; virtual void dispatchDidReceiveTitle(const String&) = 0; virtual void dispatchDidChangeIcons(IconType) = 0; virtual void dispatchDidCommitLoad(HistoryItem*, HistoryCommitType) = 0;
diff --git a/third_party/WebKit/Source/core/loader/LinkLoader.cpp b/third_party/WebKit/Source/core/loader/LinkLoader.cpp index 599b82c..4110e69 100644 --- a/third_party/WebKit/Source/core/loader/LinkLoader.cpp +++ b/third_party/WebKit/Source/core/loader/LinkLoader.cpp
@@ -339,7 +339,6 @@ OtherMessageSource, VerboseMessageLevel, String("Preload triggered for " + href.host() + href.path()))); } - linkRequest.setForPreload(true, monotonicallyIncreasingTime()); linkRequest.setLinkPreload(true); return document.loader()->startPreload(resourceType.value(), linkRequest); }
diff --git a/third_party/WebKit/Source/core/loader/PingLoader.cpp b/third_party/WebKit/Source/core/loader/PingLoader.cpp index 285980c..b17334d 100644 --- a/third_party/WebKit/Source/core/loader/PingLoader.cpp +++ b/third_party/WebKit/Source/core/loader/PingLoader.cpp
@@ -253,8 +253,9 @@ FetchContext& fetchContext = frame->document()->fetcher()->context(); - fetchContext.willStartLoadingResource(m_identifier, request, Resource::Image, - initiator, false); + fetchContext.willStartLoadingResource( + m_identifier, request, Resource::Image, initiator, + FetchContext::V8ActivityLoggingPolicy::Log); FetchInitiatorInfo initiatorInfo; initiatorInfo.name = initiator;
diff --git a/third_party/WebKit/Source/core/loader/PingLoaderTest.cpp b/third_party/WebKit/Source/core/loader/PingLoaderTest.cpp index f96f9b7..41ffc45 100644 --- a/third_party/WebKit/Source/core/loader/PingLoaderTest.cpp +++ b/third_party/WebKit/Source/core/loader/PingLoaderTest.cpp
@@ -64,6 +64,9 @@ EXPECT_EQ(destinationURL.getString(), pingRequest.httpHeaderField("Ping-To")); } + // Serve the ping request, since it will otherwise bleed in to the next + // test, and once begun there is no way to cancel it directly. + Platform::current()->getURLLoaderMockFactory()->serveAsynchronousRequests(); return pingRequest; }
diff --git a/third_party/WebKit/Source/core/loader/ProgressTrackerTest.cpp b/third_party/WebKit/Source/core/loader/ProgressTrackerTest.cpp index 64a20d05..0672f2d 100644 --- a/third_party/WebKit/Source/core/loader/ProgressTrackerTest.cpp +++ b/third_party/WebKit/Source/core/loader/ProgressTrackerTest.cpp
@@ -32,8 +32,7 @@ : m_response(KURL(ParsedURLString, "http://example.com"), "text/html", 1024, - nullAtom, - String()) {} + nullAtom) {} void SetUp() override { m_client = new ProgressClient;
diff --git a/third_party/WebKit/Source/core/loader/resource/CSSStyleSheetResourceTest.cpp b/third_party/WebKit/Source/core/loader/resource/CSSStyleSheetResourceTest.cpp index d53773f..f09d0b11 100644 --- a/third_party/WebKit/Source/core/loader/resource/CSSStyleSheetResourceTest.cpp +++ b/third_party/WebKit/Source/core/loader/resource/CSSStyleSheetResourceTest.cpp
@@ -76,7 +76,7 @@ CSSStyleSheetResource* cssResource = CSSStyleSheetResource::createForTest(ResourceRequest(cssURL), "utf-8"); cssResource->responseReceived( - ResourceResponse(cssURL, "style/css", 0, nullAtom, String()), nullptr); + ResourceResponse(cssURL, "style/css", 0, nullAtom), nullptr); cssResource->finish(); CSSParserContext* parserContext = CSSParserContext::create(HTMLStandardMode);
diff --git a/third_party/WebKit/Source/core/loader/resource/ImageResource.cpp b/third_party/WebKit/Source/core/loader/resource/ImageResource.cpp index f3c3221..1f646e2 100644 --- a/third_party/WebKit/Source/core/loader/resource/ImageResource.cpp +++ b/third_party/WebKit/Source/core/loader/resource/ImageResource.cpp
@@ -155,7 +155,12 @@ if (requestURL.isValid()) { ResourceRequestBlockedReason blockReason = fetcher->context().canRequest( Resource::Image, request.resourceRequest(), requestURL, - request.options(), request.forPreload(), + request.options(), + /* Don't send security violation reports for speculative preloads */ + request.isSpeculativePreload() + ? FetchContext::SecurityViolationReportingPolicy:: + SuppressReporting + : FetchContext::SecurityViolationReportingPolicy::Report, request.getOriginRestriction()); if (blockReason == ResourceRequestBlockedReason::None) fetcher->context().sendImagePing(requestURL);
diff --git a/third_party/WebKit/Source/core/loader/resource/ImageResourceTest.cpp b/third_party/WebKit/Source/core/loader/resource/ImageResourceTest.cpp index 7c3e7db..aa01a1e0 100644 --- a/third_party/WebKit/Source/core/loader/resource/ImageResourceTest.cpp +++ b/third_party/WebKit/Source/core/loader/resource/ImageResourceTest.cpp
@@ -183,7 +183,7 @@ const ResourceRequest&, const KURL&, const ResourceLoaderOptions&, - bool forPreload, + SecurityViolationReportingPolicy, FetchRequest::OriginRestriction) const override { return ResourceRequestBlockedReason::None; } @@ -247,7 +247,7 @@ // the response must be routed through ResourceLoader to ensure the load is // flagged as multipart. ResourceResponse multipartResponse(KURL(), "multipart/x-mixed-replace", 0, - nullAtom, String()); + nullAtom); multipartResponse.setMultipartBoundary("boundary", strlen("boundary")); imageResource->loader()->didReceiveResponse( WrappedResourceResponse(multipartResponse), nullptr); @@ -348,13 +348,11 @@ // Send the image response. imageResource->responseReceived( - ResourceResponse(KURL(), "multipart/x-mixed-replace", 0, nullAtom, - String()), + ResourceResponse(KURL(), "multipart/x-mixed-replace", 0, nullAtom), nullptr); imageResource->responseReceived( - ResourceResponse(KURL(), "image/jpeg", sizeof(kJpegImage), nullAtom, - String()), + ResourceResponse(KURL(), "image/jpeg", sizeof(kJpegImage), nullAtom), nullptr); imageResource->appendData(reinterpret_cast<const char*>(kJpegImage), sizeof(kJpegImage)); @@ -392,8 +390,7 @@ // Send the image response. imageResource->responseReceived( - ResourceResponse(KURL(), "image/jpeg", sizeof(kJpegImage), nullAtom, - String()), + ResourceResponse(KURL(), "image/jpeg", sizeof(kJpegImage), nullAtom), nullptr); imageResource->appendData(reinterpret_cast<const char*>(kJpegImage), sizeof(kJpegImage)); @@ -421,7 +418,7 @@ // Send the image response. ResourceResponse resourceResponse(KURL(), "image/jpeg", sizeof(kJpegImage), - nullAtom, String()); + nullAtom); resourceResponse.addHTTPHeaderField("chrome-proxy-content-transform", "empty-image"); @@ -485,8 +482,8 @@ MockImageResourceObserver::create(imageResource->getContent()); // Send the image response. - ResourceResponse initialResourceResponse( - testURL, "image/jpeg", sizeof(kJpegImage), nullAtom, String()); + ResourceResponse initialResourceResponse(testURL, "image/jpeg", + sizeof(kJpegImage), nullAtom); initialResourceResponse.addHTTPHeaderField("chrome-proxy", "q=low"); imageResource->loader()->didReceiveResponse( @@ -518,8 +515,8 @@ EXPECT_FALSE(observer->imageNotifyFinishedCalled()); imageResource->loader()->didReceiveResponse( - WrappedResourceResponse(ResourceResponse( - testURL, "image/jpeg", sizeof(kJpegImage2), nullAtom, String())), + WrappedResourceResponse(ResourceResponse(testURL, "image/jpeg", + sizeof(kJpegImage2), nullAtom)), nullptr); imageResource->loader()->didReceiveData( reinterpret_cast<const char*>(kJpegImage2), sizeof(kJpegImage2)); @@ -556,8 +553,7 @@ MockImageResourceObserver::create(imageResource->getContent()); ResourceResponse response(testURL, "image/jpeg", - kJpegImageSubrangeWithDimensionsLength, nullAtom, - String()); + kJpegImageSubrangeWithDimensionsLength, nullAtom); response.setHTTPStatusCode(206); response.setHTTPHeaderField( "content-range", buildContentRange(kJpegImageSubrangeWithDimensionsLength, @@ -860,7 +856,7 @@ imageResource->loader()->didReceiveResponse( WrappedResourceResponse( - ResourceResponse(testURL, "image/jpeg", 18, nullAtom, String())), + ResourceResponse(testURL, "image/jpeg", 18, nullAtom)), nullptr); EXPECT_EQ(0, observer->imageChangedCount()); @@ -888,7 +884,7 @@ imageResource->loader()->didReceiveResponse( WrappedResourceResponse( - ResourceResponse(testURL, "image/jpeg", 0, nullAtom, String())), + ResourceResponse(testURL, "image/jpeg", 0, nullAtom)), nullptr); EXPECT_EQ(ResourceStatus::Pending, imageResource->getStatus()); @@ -921,9 +917,8 @@ std::unique_ptr<MockImageResourceObserver> observer = MockImageResourceObserver::create(imageResource->getContent()); - imageResource->loader()->didReceiveResponse( - WrappedResourceResponse(ResourceResponse( - testURL, "image/jpeg", sizeof(kJpegImage), nullAtom, String()))); + imageResource->loader()->didReceiveResponse(WrappedResourceResponse( + ResourceResponse(testURL, "image/jpeg", sizeof(kJpegImage), nullAtom))); imageResource->loader()->didReceiveData( reinterpret_cast<const char*>(kJpegImage), sizeof(kJpegImage)); imageResource->loader()->didFinishLoading(0.0, sizeof(kJpegImage), @@ -1016,8 +1011,7 @@ MockImageResourceObserver::create(imageResource->getContent()); ResourceResponse response(testURL, "image/jpeg", - kJpegImageSubrangeWithDimensionsLength, nullAtom, - String()); + kJpegImageSubrangeWithDimensionsLength, nullAtom); response.setHTTPStatusCode(206); response.setHTTPHeaderField( "content-range", buildContentRange(kJpegImageSubrangeWithDimensionsLength, @@ -1066,9 +1060,8 @@ const char kBadData[] = "notanimageresponse"; - imageResource->loader()->didReceiveResponse( - WrappedResourceResponse(ResourceResponse( - testURL, "image/jpeg", sizeof(kBadData), nullAtom, String()))); + imageResource->loader()->didReceiveResponse(WrappedResourceResponse( + ResourceResponse(testURL, "image/jpeg", sizeof(kBadData), nullAtom))); EXPECT_EQ(0, observer->imageChangedCount()); @@ -1086,9 +1079,8 @@ EXPECT_FALSE(observer->imageNotifyFinishedCalled()); EXPECT_EQ(3, observer->imageChangedCount()); - imageResource->loader()->didReceiveResponse( - WrappedResourceResponse(ResourceResponse( - testURL, "image/jpeg", sizeof(kJpegImage), nullAtom, String()))); + imageResource->loader()->didReceiveResponse(WrappedResourceResponse( + ResourceResponse(testURL, "image/jpeg", sizeof(kJpegImage), nullAtom))); imageResource->loader()->didReceiveData( reinterpret_cast<const char*>(kJpegImage), sizeof(kJpegImage)); imageResource->loader()->didFinishLoading(0.0, sizeof(kJpegImage), @@ -1152,8 +1144,7 @@ MockImageResourceObserver::create(imageResource->getContent()); ResourceResponse response(testURL, "image/jpeg", - kJpegImageSubrangeWithDimensionsLength, nullAtom, - String()); + kJpegImageSubrangeWithDimensionsLength, nullAtom); response.setHTTPStatusCode(206); response.setHTTPHeaderField( "content-range", buildContentRange(kJpegImageSubrangeWithDimensionsLength, @@ -1203,7 +1194,7 @@ // Send the image response. ResourceResponse resourceResponse(KURL(), "image/jpeg", sizeof(kJpegImage2), - nullAtom, String()); + nullAtom); resourceResponse.addHTTPHeaderField("chrome-proxy", "q=low"); imageResource->responseReceived(resourceResponse, nullptr);
diff --git a/third_party/WebKit/Source/core/page/ChromeClient.h b/third_party/WebKit/Source/core/page/ChromeClient.h index 66b4ea06..01e2941 100644 --- a/third_party/WebKit/Source/core/page/ChromeClient.h +++ b/third_party/WebKit/Source/core/page/ChromeClient.h
@@ -310,7 +310,6 @@ virtual void ajaxSucceeded(LocalFrame*) {} // Input method editor related functions. - virtual void didCancelCompositionOnSelectionChange() {} virtual void resetInputMethod() {} virtual void didUpdateTextOfFocusedElementByNonUserInput(LocalFrame&) {} virtual void showVirtualKeyboardOnElementFocus() {}
diff --git a/third_party/WebKit/Source/core/page/DragController.cpp b/third_party/WebKit/Source/core/page/DragController.cpp index 07385275..b4ff410 100644 --- a/third_party/WebKit/Source/core/page/DragController.cpp +++ b/third_party/WebKit/Source/core/page/DragController.cpp
@@ -861,8 +861,7 @@ .setBaseAndExtent(EphemeralRange(range)) .build()); } - dataTransfer->declareAndWriteDragImage( - node, !linkURL.isEmpty() ? linkURL : imageURL, label); + dataTransfer->declareAndWriteDragImage(node, linkURL, imageURL, label); } bool DragController::populateDragDataTransfer(LocalFrame* src,
diff --git a/third_party/WebKit/Source/core/paint/BlockPaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/BlockPaintInvalidator.cpp index b64c32e..a7db1eb 100644 --- a/third_party/WebKit/Source/core/paint/BlockPaintInvalidator.cpp +++ b/third_party/WebKit/Source/core/paint/BlockPaintInvalidator.cpp
@@ -4,23 +4,32 @@ #include "core/paint/BlockPaintInvalidator.h" +#include "core/editing/DragCaret.h" #include "core/editing/FrameSelection.h" #include "core/frame/LocalFrame.h" #include "core/layout/LayoutBlock.h" +#include "core/page/Page.h" #include "core/paint/BoxPaintInvalidator.h" +#include "core/paint/ObjectPaintInvalidator.h" #include "core/paint/PaintInvalidator.h" namespace blink { -PaintInvalidationReason BlockPaintInvalidator::invalidatePaintIfNeeded() { - PaintInvalidationReason reason = - BoxPaintInvalidator(m_block, m_context).invalidatePaintIfNeeded(); +void BlockPaintInvalidator::clearPreviousVisualRects() { + m_block.frame()->selection().clearPreviousCaretVisualRect(m_block); + m_block.frame()->page()->dragCaret().clearPreviousVisualRect(m_block); +} - if (reason != PaintInvalidationNone && m_block.hasCaret()) { - FrameSelection& selection = m_block.frame()->selection(); - selection.setCaretRectNeedsUpdate(); - selection.invalidateCaretRect(true); - } +PaintInvalidationReason BlockPaintInvalidator::invalidatePaintIfNeeded( + const PaintInvalidatorContext& context) { + PaintInvalidationReason reason = + BoxPaintInvalidator(m_block, context).invalidatePaintIfNeeded(); + + m_block.frame()->selection().invalidatePaintIfNeeded(m_block, context, + reason); + m_block.frame()->page()->dragCaret().invalidatePaintIfNeeded(m_block, context, + reason); + return reason; } }
diff --git a/third_party/WebKit/Source/core/paint/BlockPaintInvalidator.h b/third_party/WebKit/Source/core/paint/BlockPaintInvalidator.h index ff759f8b..ac03658b 100644 --- a/third_party/WebKit/Source/core/paint/BlockPaintInvalidator.h +++ b/third_party/WebKit/Source/core/paint/BlockPaintInvalidator.h
@@ -17,15 +17,14 @@ STACK_ALLOCATED(); public: - BlockPaintInvalidator(const LayoutBlock& block, - const PaintInvalidatorContext& context) - : m_block(block), m_context(context) {} + BlockPaintInvalidator(const LayoutBlock& block) : m_block(block) {} - PaintInvalidationReason invalidatePaintIfNeeded(); + void clearPreviousVisualRects(); + PaintInvalidationReason invalidatePaintIfNeeded( + const PaintInvalidatorContext&); private: const LayoutBlock& m_block; - const PaintInvalidatorContext& m_context; }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/BlockPaintInvalidatorTest.cpp b/third_party/WebKit/Source/core/paint/BlockPaintInvalidatorTest.cpp new file mode 100644 index 0000000..0f3868d --- /dev/null +++ b/third_party/WebKit/Source/core/paint/BlockPaintInvalidatorTest.cpp
@@ -0,0 +1,135 @@ +// 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 "core/HTMLNames.h" +#include "core/editing/FrameSelection.h" +#include "core/frame/FrameView.h" +#include "core/layout/LayoutTestHelper.h" +#include "core/layout/LayoutView.h" +#include "core/page/FocusController.h" +#include "core/paint/PaintLayer.h" +#include "platform/graphics/GraphicsLayer.h" +#include "platform/graphics/paint/RasterInvalidationTracking.h" + +namespace blink { + +class BlockPaintInvalidatorTest : public RenderingTest { + protected: + void SetUp() override { + RenderingTest::SetUp(); + enableCompositing(); + } + + const RasterInvalidationTracking* getRasterInvalidationTracking() const { + // TODO(wangxianzhu): Test SPv2. + return layoutView() + .layer() + ->graphicsLayerBacking() + ->getRasterInvalidationTracking(); + } + + FrameSelection& selection() const { + return document().view()->frame().selection(); + } + + const DisplayItemClient& caretDisplayItemClient() const { + return selection().caretDisplayItemClientForTesting(); + } + + Text* appendTextNode(const String& data) { + Text* text = document().createTextNode(data); + document().body()->appendChild(text); + return text; + } +}; + +TEST_F(BlockPaintInvalidatorTest, CaretPaintInvalidation) { + document().body()->setContentEditable("true", ASSERT_NO_EXCEPTION); + document().page()->focusController().setActive(true); + document().page()->focusController().setFocused(true); + + Text* text = appendTextNode("Hello, World!"); + document().view()->updateAllLifecyclePhases(); + const auto* block = toLayoutBlock(document().body()->layoutObject()); + + // Focus the body. Should invalidate the new caret. + document().view()->setTracksPaintInvalidations(true); + document().body()->focus(); + document().view()->updateAllLifecyclePhases(); + EXPECT_TRUE(block->shouldPaintCursorCaret()); + + LayoutRect caretVisualRect = caretDisplayItemClient().visualRect(); + EXPECT_EQ(1, caretVisualRect.width()); + EXPECT_EQ(block->location(), caretVisualRect.location()); + + const auto* rasterInvalidations = + &getRasterInvalidationTracking()->trackedRasterInvalidations; + ASSERT_EQ(1u, rasterInvalidations->size()); + EXPECT_EQ(enclosingIntRect(caretVisualRect), (*rasterInvalidations)[0].rect); + EXPECT_EQ(block, (*rasterInvalidations)[0].client); + EXPECT_EQ(PaintInvalidationCaret, (*rasterInvalidations)[0].reason); + + std::unique_ptr<JSONArray> objectInvalidations = + document().view()->trackedObjectPaintInvalidationsAsJSON(); + ASSERT_EQ(1u, objectInvalidations->size()); + String s; + JSONObject::cast(objectInvalidations->at(0))->get("object")->asString(&s); + EXPECT_EQ("Caret", s); + document().view()->setTracksPaintInvalidations(false); + + // Move the caret to the end of the text. Should invalidate both the old and + // new carets. + document().view()->setTracksPaintInvalidations(true); + selection().setSelection( + SelectionInDOMTree::Builder().collapse(Position(text, 5)).build()); + document().view()->updateAllLifecyclePhases(); + EXPECT_TRUE(block->shouldPaintCursorCaret()); + + LayoutRect newCaretVisualRect = caretDisplayItemClient().visualRect(); + EXPECT_EQ(caretVisualRect.size(), newCaretVisualRect.size()); + EXPECT_EQ(caretVisualRect.y(), newCaretVisualRect.y()); + EXPECT_LT(caretVisualRect.x(), newCaretVisualRect.x()); + + rasterInvalidations = + &getRasterInvalidationTracking()->trackedRasterInvalidations; + ASSERT_EQ(2u, rasterInvalidations->size()); + EXPECT_EQ(enclosingIntRect(caretVisualRect), (*rasterInvalidations)[0].rect); + EXPECT_EQ(block, (*rasterInvalidations)[0].client); + EXPECT_EQ(PaintInvalidationCaret, (*rasterInvalidations)[0].reason); + EXPECT_EQ(enclosingIntRect(newCaretVisualRect), + (*rasterInvalidations)[1].rect); + EXPECT_EQ(block, (*rasterInvalidations)[1].client); + EXPECT_EQ(PaintInvalidationCaret, (*rasterInvalidations)[1].reason); + + objectInvalidations = + document().view()->trackedObjectPaintInvalidationsAsJSON(); + ASSERT_EQ(1u, objectInvalidations->size()); + JSONObject::cast(objectInvalidations->at(0))->get("object")->asString(&s); + EXPECT_EQ("Caret", s); + document().view()->setTracksPaintInvalidations(false); + + // Remove selection. Should invalidate the old caret. + LayoutRect oldCaretVisualRect = newCaretVisualRect; + document().view()->setTracksPaintInvalidations(true); + selection().setSelection(SelectionInDOMTree()); + document().view()->updateAllLifecyclePhases(); + EXPECT_FALSE(block->shouldPaintCursorCaret()); + EXPECT_EQ(LayoutRect(), caretDisplayItemClient().visualRect()); + + rasterInvalidations = + &getRasterInvalidationTracking()->trackedRasterInvalidations; + ASSERT_EQ(1u, rasterInvalidations->size()); + EXPECT_EQ(enclosingIntRect(oldCaretVisualRect), + (*rasterInvalidations)[0].rect); + EXPECT_EQ(block, (*rasterInvalidations)[0].client); + + objectInvalidations = + document().view()->trackedObjectPaintInvalidationsAsJSON(); + ASSERT_EQ(1u, objectInvalidations->size()); + JSONObject::cast(objectInvalidations->at(0))->get("object")->asString(&s); + EXPECT_EQ("Caret", s); + document().view()->setTracksPaintInvalidations(false); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/BlockPainter.cpp b/third_party/WebKit/Source/core/paint/BlockPainter.cpp index 067bd04e..59aeae5 100644 --- a/third_party/WebKit/Source/core/paint/BlockPainter.cpp +++ b/third_party/WebKit/Source/core/paint/BlockPainter.cpp
@@ -43,7 +43,7 @@ // FIXME: reduce the number of such cases. ContentsClipBehavior contentsClipBehavior = ForceContentsClip; if (m_layoutBlock.shouldClipOverflow() && !m_layoutBlock.hasControlClip() && - !m_layoutBlock.hasCaret()) + !m_layoutBlock.shouldPaintCarets()) contentsClipBehavior = SkipContentsClipIfPossible; if (originalPhase == PaintPhaseOutline) { @@ -246,7 +246,7 @@ // If the caret's node's layout object's containing block is this block, and // the paint action is PaintPhaseForeground, then paint the caret. - if (paintPhase == PaintPhaseForeground && m_layoutBlock.hasCaret()) + if (paintPhase == PaintPhaseForeground && m_layoutBlock.shouldPaintCarets()) paintCarets(paintInfo, paintOffset); } @@ -254,10 +254,10 @@ const LayoutPoint& paintOffset) { LocalFrame* frame = m_layoutBlock.frame(); - if (m_layoutBlock.hasCursorCaret()) + if (m_layoutBlock.shouldPaintCursorCaret()) frame->selection().paintCaret(paintInfo.context, paintOffset); - if (m_layoutBlock.hasDragCaret()) { + if (m_layoutBlock.shouldPaintDragCaret()) { frame->page()->dragCaret().paintDragCaret(frame, paintInfo.context, paintOffset); }
diff --git a/third_party/WebKit/Source/core/paint/ObjectPaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/ObjectPaintInvalidator.cpp index 46dd61c..15e0406 100644 --- a/third_party/WebKit/Source/core/paint/ObjectPaintInvalidator.cpp +++ b/third_party/WebKit/Source/core/paint/ObjectPaintInvalidator.cpp
@@ -318,7 +318,8 @@ rect, reason, m_object); } else if (paintInvalidationContainer.usesCompositedScrolling()) { DCHECK(m_object == paintInvalidationContainer); - if (reason == PaintInvalidationBackgroundOnScrollingContentsLayer) { + if (reason == PaintInvalidationBackgroundOnScrollingContentsLayer || + reason == PaintInvalidationCaret) { layer.compositedLayerMapping()->setScrollingContentsNeedDisplayInRect( rect, reason, m_object); } else {
diff --git a/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp index 162dba32..ab809a3 100644 --- a/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp +++ b/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp
@@ -117,8 +117,11 @@ PropertyTreeState currentTreeState( context.treeBuilderContext.current.transform, context.treeBuilderContext.current.clip, nullptr); - result = LayoutRect(geometryMapper.sourceToDestinationVisualRect( - FloatRect(rect), currentTreeState, *containerContentsProperties)); + result = LayoutRect( + geometryMapper + .sourceToDestinationVisualRect(FloatRect(rect), currentTreeState, + *containerContentsProperties) + .rect()); } // Convert the result to the container's contents space. @@ -370,8 +373,6 @@ ScopedUndoFrameViewContentClipAndScroll undo(frameView, context); frameView.invalidatePaintOfScrollControlsIfNeeded(context); } - - frameView.frame().selection().invalidateCaretRect(); } void PaintInvalidator::invalidatePaintIfNeeded(
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp b/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp index b8b71d4..ce81f14 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp
@@ -206,10 +206,9 @@ const PaintLayer& clippingRootLayer) const { ClipRectsContext context(&clippingRootLayer, PaintingClipRects); if (m_geometryMapper) { - LayoutRect premappedRect = - applyOverflowClipToBackgroundRectWithGeometryMapper( - context, clipRectWithGeometryMapper(context, false)) - .rect(); + ClipRect clipRect = clipRectWithGeometryMapper(context, false); + applyOverflowClipToBackgroundRectWithGeometryMapper(context, clipRect); + LayoutRect premappedRect = clipRect.rect(); // The rect now needs to be transformed to the local space of this // PaintLayer. @@ -283,8 +282,9 @@ ClipRect& backgroundRect, ClipRect& foregroundRect, const LayoutPoint* offsetFromRoot) const { - backgroundRect = applyOverflowClipToBackgroundRectWithGeometryMapper( - context, clipRectWithGeometryMapper(context, false)); + backgroundRect = clipRectWithGeometryMapper(context, false); + applyOverflowClipToBackgroundRectWithGeometryMapper(context, backgroundRect); + backgroundRect.move( context.subPixelAccumulation); // TODO(chrishtr): is this needed? backgroundRect.intersect(paintDirtyRect); @@ -466,34 +466,34 @@ propertyTreeState.setClip(properties->overflowClip()); } - FloatRect clippedRectInRootLayerSpace = + FloatClipRect clippedRectInRootLayerSpace = m_geometryMapper->sourceToDestinationVisualRect( FloatRect(source), propertyTreeState, destinationPropertyTreeState); - clippedRectInRootLayerSpace.moveBy( - -FloatPoint(context.rootLayer->layoutObject()->paintOffset())); - return ClipRect(LayoutRect(clippedRectInRootLayerSpace)); + ClipRect clipRect(LayoutRect(clippedRectInRootLayerSpace.rect())); + if (clippedRectInRootLayerSpace.hasRadius()) + clipRect.setHasRadius(true); + + clipRect.moveBy(-context.rootLayer->layoutObject()->paintOffset()); + return clipRect; } -ClipRect PaintLayerClipper::applyOverflowClipToBackgroundRectWithGeometryMapper( +void PaintLayerClipper::applyOverflowClipToBackgroundRectWithGeometryMapper( const ClipRectsContext& context, - const ClipRect& clip) const { + ClipRect& clip) const { const LayoutObject& layoutObject = *m_layer.layoutObject(); - FloatRect clipRect(clip.rect()); - if (shouldClipOverflow(context)) { - LayoutRect layerBoundsWithVisualOverflow = - layoutObject.isLayoutView() - ? toLayoutView(layoutObject).viewRect() - : toLayoutBox(layoutObject).visualOverflowRect(); - toLayoutBox(layoutObject) - .flipForWritingMode( - // PaintLayer are in physical coordinates, so the overflow has to be - // flipped. - layerBoundsWithVisualOverflow); - mapLocalToRootWithGeometryMapper(context, layerBoundsWithVisualOverflow); - clipRect.intersect(FloatRect(layerBoundsWithVisualOverflow)); - } - - return ClipRect(LayoutRect(clipRect)); + if (!shouldClipOverflow(context)) + return; + LayoutRect layerBoundsWithVisualOverflow = + layoutObject.isLayoutView() + ? toLayoutView(layoutObject).viewRect() + : toLayoutBox(layoutObject).visualOverflowRect(); + toLayoutBox(layoutObject) + .flipForWritingMode( + // PaintLayer are in physical coordinates, so the overflow has to be + // flipped. + layerBoundsWithVisualOverflow); + mapLocalToRootWithGeometryMapper(context, layerBoundsWithVisualOverflow); + clip.intersect(layerBoundsWithVisualOverflow); } ClipRect PaintLayerClipper::backgroundClipRect(
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerClipper.h b/third_party/WebKit/Source/core/paint/PaintLayerClipper.h index 3dc9a19..de1ed70 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerClipper.h +++ b/third_party/WebKit/Source/core/paint/PaintLayerClipper.h
@@ -230,9 +230,9 @@ ClipRect& foregroundRect, const LayoutPoint* offsetFromRoot = 0) const; - ClipRect applyOverflowClipToBackgroundRectWithGeometryMapper( + void applyOverflowClipToBackgroundRectWithGeometryMapper( const ClipRectsContext&, - const ClipRect&) const; + ClipRect&) const; const PaintLayer& m_layer; std::unique_ptr<GeometryMapper> m_geometryMapper;
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerClipperTest.cpp b/third_party/WebKit/Source/core/paint/PaintLayerClipperTest.cpp index 618e481c..6786b27 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerClipperTest.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayerClipperTest.cpp
@@ -101,6 +101,70 @@ #endif } +TEST_P(PaintLayerClipperTest, RoundedClip) { + setBodyInnerHTML( + "<!DOCTYPE html>" + "<div id='target' style='position:absolute; width: 200px; height: 300px;" + " overflow: hidden; border-radius: 1px'>" + "</div>"); + + Element* target = document().getElementById("target"); + PaintLayer* targetPaintLayer = + toLayoutBoxModelObject(target->layoutObject())->layer(); + ClipRectsContext context(document().layoutView()->layer(), UncachedClipRects); + // When RLS is enabled, the LayoutView will have a composited scrolling layer, + // so don't apply an overflow clip. + if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) + context.setIgnoreOverflowClip(); + + LayoutRect layerBounds; + ClipRect backgroundRect, foregroundRect; + targetPaintLayer->clipper().calculateRects( + context, LayoutRect(LayoutRect::infiniteIntRect()), layerBounds, + backgroundRect, foregroundRect); + + // Only the foreground rect gets hasRadius set for overflow clipping + // of descendants. + EXPECT_EQ(LayoutRect(8, 8, 200, 300), backgroundRect.rect()); + EXPECT_FALSE(backgroundRect.hasRadius()); + EXPECT_EQ(LayoutRect(8, 8, 200, 300), foregroundRect.rect()); + EXPECT_TRUE(foregroundRect.hasRadius()); + EXPECT_EQ(LayoutRect(8, 8, 200, 300), layerBounds); +} + +TEST_P(PaintLayerClipperTest, RoundedClipNested) { + setBodyInnerHTML( + "<!DOCTYPE html>" + "<div id='parent' style='position:absolute; width: 200px; height: 300px;" + " overflow: hidden; border-radius: 1px'>" + " <div id='child' style='position: relative; width: 500px; " + " height: 500px'>" + " </div>" + "</div>"); + + Element* parent = document().getElementById("parent"); + PaintLayer* parentPaintLayer = + toLayoutBoxModelObject(parent->layoutObject())->layer(); + + Element* child = document().getElementById("child"); + PaintLayer* childPaintLayer = + toLayoutBoxModelObject(child->layoutObject())->layer(); + + ClipRectsContext context(parentPaintLayer, UncachedClipRects); + + LayoutRect layerBounds; + ClipRect backgroundRect, foregroundRect; + childPaintLayer->clipper().calculateRects( + context, LayoutRect(LayoutRect::infiniteIntRect()), layerBounds, + backgroundRect, foregroundRect); + + EXPECT_EQ(LayoutRect(0, 0, 200, 300), backgroundRect.rect()); + EXPECT_TRUE(backgroundRect.hasRadius()); + EXPECT_EQ(LayoutRect(0, 0, 200, 300), foregroundRect.rect()); + EXPECT_TRUE(foregroundRect.hasRadius()); + EXPECT_EQ(LayoutRect(0, 0, 500, 500), layerBounds); +} + TEST_P(PaintLayerClipperTest, ControlClipSelect) { setBodyInnerHTML( "<select id='target' style='position: relative; width: 100px; "
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp index d025478f..d3f78ad 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
@@ -409,8 +409,6 @@ const LayoutBoxModelObject& paintInvalidationContainer = box().containerForPaintInvalidation(); - // The caret rect needs to be invalidated after scrolling - frame->selection().setCaretRectNeedsUpdate(); FloatQuad quadForFakeMouseMoveEvent = FloatQuad(FloatRect( layer()->layoutObject()->previousVisualRectIncludingCompositedScrolling(
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp index dfcc403..f2e106b 100644 --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
@@ -83,12 +83,14 @@ source.moveBy((sourceLayoutObject)->paintOffset()); \ const auto& contentsProperties = \ *(ancestorLayoutObject)->paintProperties()->contentsProperties(); \ - LayoutRect actual = \ - LayoutRect(geometryMapper.sourceToDestinationVisualRect( \ - FloatRect(source), *(sourceLayoutObject) \ - ->paintProperties() \ - ->localBorderBoxProperties(), \ - contentsProperties)); \ + LayoutRect actual = LayoutRect( \ + geometryMapper \ + .sourceToDestinationVisualRect(FloatRect(source), \ + *(sourceLayoutObject) \ + ->paintProperties() \ + ->localBorderBoxProperties(), \ + contentsProperties) \ + .rect()); \ actual.moveBy(-(ancestorLayoutObject)->paintOffset()); \ EXPECT_EQ(expected, actual) \ << "GeometryMapper: expected: " << expected.toString() \
diff --git a/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp b/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp index 5514ca0c..0152a5f8 100644 --- a/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp +++ b/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp
@@ -121,8 +121,10 @@ // TODO(chrishtr): remove need for this. LayoutRect localRect(LayoutRect::infiniteIntRect()); - LayoutRect rect(m_geometryMapper.sourceToDestinationVisualRect( - FloatRect(localRect), localState, ancestorState)); + LayoutRect rect(m_geometryMapper + .sourceToDestinationVisualRect(FloatRect(localRect), + localState, ancestorState) + .rect()); rect.moveBy(-ancestorPaintOffset); return rect; }
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h index df10f01..cdd71835 100644 --- a/third_party/WebKit/Source/core/style/ComputedStyle.h +++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -2539,7 +2539,7 @@ bool emptyState() const { return m_nonInheritedData.m_emptyState; } void setEmptyState(bool b) { - setUnique(); + setUnique(true); m_nonInheritedData.m_emptyState = b; } @@ -2612,7 +2612,7 @@ // A unique style is one that has matches something that makes it impossible // to share. bool unique() const { return m_nonInheritedData.m_unique; } - void setUnique() { m_nonInheritedData.m_unique = true; } + void setUnique(bool v) { m_nonInheritedData.m_unique = v; } float textAutosizingMultiplier() const { return m_styleInheritedData->textAutosizingMultiplier;
diff --git a/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js b/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js index c9920b02..97f701c 100644 --- a/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js +++ b/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js
@@ -1052,7 +1052,7 @@ this._messageLevelFiltersSetting.addChangeListener(this._filterChanged); this._hideNetworkMessagesSetting.addChangeListener(this._filterChanged); - this._textFilterUI = new UI.ToolbarInput(Common.UIString('Filter'), 0.2, 1); + this._textFilterUI = new UI.ToolbarInput(Common.UIString('Filter'), 0.2, 1, true); this._textFilterUI.addEventListener(UI.ToolbarInput.Event.TextChanged, this._textFilterChanged, this); var levels = [
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js index 82a5a0d..9325f06 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js +++ b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
@@ -2344,7 +2344,6 @@ if (selectElement.parentElement) selectElement.parentElement.scrollIntoViewIfNeeded(false); - var applyItemCallback = !isEditingName ? this._applyFreeFlowStyleTextEdit.bind(this) : undefined; var cssCompletions = []; if (isEditingName) { cssCompletions = SDK.cssMetadata().allProperties(); @@ -2357,16 +2356,16 @@ this._prompt = new Elements.StylesSidebarPane.CSSPropertyPrompt(cssCompletions, cssVariables, this, isEditingName); this._prompt.setAutocompletionTimeout(0); - if (applyItemCallback) { - this._prompt.addEventListener(UI.TextPrompt.Events.ItemApplied, applyItemCallback, this); - this._prompt.addEventListener(UI.TextPrompt.Events.ItemAccepted, applyItemCallback, this); - } + + // Do not live-edit "content" property of pseudo elements. crbug.com/433889 + if (!isEditingName && (!this._parentPane.node().pseudoType() || this.name !== 'content')) + this._prompt.on(UI.TextPrompt.TextChangedEvent, this._applyFreeFlowStyleTextEdit.bind(this)); + var proxyElement = this._prompt.attachAndStartEditing(selectElement, blurListener.bind(this, context)); this._navigateToSource(selectElement, true); proxyElement.addEventListener('keydown', this._editingNameValueKeyDown.bind(this, context), false); proxyElement.addEventListener('keypress', this._editingNameValueKeyPress.bind(this, context), false); - proxyElement.addEventListener('input', this._editingNameValueInput.bind(this, context), false); if (isEditingName) proxyElement.addEventListener('paste', pasteHandler.bind(this, context), false); @@ -2455,16 +2454,6 @@ } } - /** - * @param {!Elements.StylePropertyTreeElement.Context} context - * @param {!Event} event - */ - _editingNameValueInput(context, event) { - // Do not live-edit "content" property of pseudo elements. crbug.com/433889 - if (!context.isEditingName && (!this._parentPane.node().pseudoType() || this.name !== 'content')) - this._applyFreeFlowStyleTextEdit(); - } - _applyFreeFlowStyleTextEdit() { var valueText = this._prompt.textWithCurrentSuggestion(); if (valueText.indexOf(';') === -1)
diff --git a/third_party/WebKit/Source/devtools/front_end/gonzales/gonzales-scss.js b/third_party/WebKit/Source/devtools/front_end/gonzales/gonzales-scss.js index 6ad1dbc..f09d2159 100644 --- a/third_party/WebKit/Source/devtools/front_end/gonzales/gonzales-scss.js +++ b/third_party/WebKit/Source/devtools/front_end/gonzales/gonzales-scss.js
@@ -60,7 +60,7 @@ var parse = __webpack_require__(7); module.exports = { - createNode: function (options) { + createNode: function createNode(options) { return new Node(options); }, parse: parse @@ -80,11 +80,11 @@ * @constructor */ - var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - var Node = (function () { + var Node = function () { function Node(options) { _classCallCheck(this, Node); @@ -101,6 +101,7 @@ * @return {Boolean} Whether there is a child node of given type */ + Node.prototype.contains = function contains(type) { return this.content.some(function (node) { return node.type === type; @@ -112,6 +113,7 @@ * @param {Function} callback Function to call for every found node */ + Node.prototype.eachFor = function eachFor(type, callback) { if (!Array.isArray(this.content)) return; @@ -137,6 +139,7 @@ * @return {?Node} First child node or `null` if nothing's been found. */ + Node.prototype.first = function first(type) { if (!Array.isArray(this.content)) return null; @@ -157,6 +160,7 @@ * @param {Function} callback Function to call for every found node */ + Node.prototype.forEach = function forEach(type, callback) { if (!Array.isArray(this.content)) return; @@ -183,6 +187,7 @@ * @return {?Node} */ + Node.prototype.get = function get(index) { if (!Array.isArray(this.content)) return null; @@ -195,6 +200,7 @@ * @param {Node} node */ + Node.prototype.insert = function insert(index, node) { if (!Array.isArray(this.content)) return; @@ -206,6 +212,7 @@ * @return {Boolean} Whether the node is of given type */ + Node.prototype.is = function is(type) { return this.type === type; }; @@ -215,13 +222,14 @@ * @return {?Node} Last child node or `null` if nothing's been found. */ + Node.prototype.last = function last(type) { if (!Array.isArray(this.content)) return null; - var i = this.content.length - 1; - if (!type) return this.content[i]; + var i = this.content.length; + if (!type) return this.content[i - 1]; - for (;; i--) { + for (; i--;) { if (this.content[i].type === type) return this.content[i]; } @@ -233,11 +241,11 @@ * @type {number} */ + /** * @param {Number} index * @return {Node} */ - Node.prototype.removeChild = function removeChild(index) { if (!Array.isArray(this.content)) return; @@ -251,7 +259,7 @@ }; Node.prototype.toString = function toString() { - var stringify = undefined; + var stringify = void 0; try { stringify = __webpack_require__(2)("./" + this.syntax + '/stringify'); @@ -267,9 +275,10 @@ * @param {Function} callback */ + Node.prototype.traverse = function traverse(callback, index) { - var level = arguments.length <= 2 || arguments[2] === undefined ? 0 : arguments[2]; - var parent = arguments.length <= 3 || arguments[3] === undefined ? null : arguments[3]; + var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; + var parent = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; var breakLoop; var x; @@ -308,14 +317,14 @@ _createClass(Node, [{ key: 'length', - get: function () { + get: function get() { if (!Array.isArray(this.content)) return 0; return this.content.length; } }]); return Node; - })(); + }(); module.exports = Node; @@ -347,8 +356,6 @@ /* 3 */ /***/ function(module, exports) { - // jscs:disable maximumLineLength - 'use strict'; module.exports = function stringify(tree) { @@ -368,57 +375,61 @@ var s = ''; i = i || 0; - for (; i < t.length; i++) s += _t(t[i]); - return s; + for (; i < t.length; i++) { + s += _t(t[i]); + }return s; } var _unique = { - 'arguments': function (t) { + 'arguments': function _arguments(t) { return '(' + _composite(t.content) + ')'; }, - 'atkeyword': function (t) { + 'atkeyword': function atkeyword(t) { return '@' + _composite(t.content); }, - 'attributeSelector': function (t) { + 'attributeSelector': function attributeSelector(t) { return '[' + _composite(t.content) + ']'; }, - 'block': function (t) { + 'block': function block(t) { return '{' + _composite(t.content) + '}'; }, - 'brackets': function (t) { + 'brackets': function brackets(t) { return '[' + _composite(t.content) + ']'; }, - 'class': function (t) { + 'class': function _class(t) { return '.' + _composite(t.content); }, - 'color': function (t) { + 'color': function color(t) { return '#' + t.content; }, - 'expression': function (t) { + 'expression': function expression(t) { return 'expression(' + t.content + ')'; }, - 'id': function (t) { + 'id': function id(t) { return '#' + _composite(t.content); }, - 'multilineComment': function (t) { + 'multilineComment': function multilineComment(t) { return '/*' + t.content + '*/'; }, - 'nthSelector': function (t) { + 'nthSelector': function nthSelector(t) { return ':' + _t(t.content[0]) + '(' + _composite(t.content.slice(1)) + ')'; }, - 'parentheses': function (t) { + 'parentheses': function parentheses(t) { return '(' + _composite(t.content) + ')'; }, - 'percentage': function (t) { + 'percentage': function percentage(t) { return _composite(t.content) + '%'; }, - 'pseudoClass': function (t) { + 'pseudoClass': function pseudoClass(t) { return ':' + _composite(t.content); }, - 'pseudoElement': function (t) { + 'pseudoElement': function pseudoElement(t) { return '::' + _composite(t.content); }, - 'uri': function (t) { + 'universalSelector': function universalSelector(t) { + return _composite(t.content) + '*'; + }, + 'uri': function uri(t) { return 'url(' + _composite(t.content) + ')'; } }; @@ -430,8 +441,6 @@ /* 4 */ /***/ function(module, exports) { - // jscs:disable maximumLineLength - 'use strict'; module.exports = function stringify(tree) { @@ -451,72 +460,76 @@ var s = ''; i = i || 0; - for (; i < t.length; i++) s += _t(t[i]); - return s; + for (; i < t.length; i++) { + s += _t(t[i]); + }return s; } var _unique = { - 'arguments': function (t) { + 'arguments': function _arguments(t) { return '(' + _composite(t.content) + ')'; }, - 'atkeyword': function (t) { + 'atkeyword': function atkeyword(t) { return '@' + _composite(t.content); }, - 'attributeSelector': function (t) { + 'attributeSelector': function attributeSelector(t) { return '[' + _composite(t.content) + ']'; }, - 'block': function (t) { + 'block': function block(t) { return '{' + _composite(t.content) + '}'; }, - 'brackets': function (t) { + 'brackets': function brackets(t) { return '[' + _composite(t.content) + ']'; }, - 'class': function (t) { + 'class': function _class(t) { return '.' + _composite(t.content); }, - 'color': function (t) { + 'color': function color(t) { return '#' + t.content; }, - 'escapedString': function (t) { + 'escapedString': function escapedString(t) { return '~' + t.content; }, - 'expression': function (t) { + 'expression': function expression(t) { return 'expression(' + t.content + ')'; }, - 'id': function (t) { + 'id': function id(t) { return '#' + _composite(t.content); }, - 'interpolatedVariable': function (t) { + 'interpolatedVariable': function interpolatedVariable(t) { return '@{' + _composite(t.content) + '}'; }, - 'multilineComment': function (t) { + 'multilineComment': function multilineComment(t) { return '/*' + t.content + '*/'; }, - 'nthSelector': function (t) { + 'nthSelector': function nthSelector(t) { return ':' + _t(t.content[0]) + '(' + _composite(t.content.slice(1)) + ')'; }, - 'parentheses': function (t) { + 'parentheses': function parentheses(t) { return '(' + _composite(t.content) + ')'; }, - 'percentage': function (t) { + 'percentage': function percentage(t) { return _composite(t.content) + '%'; }, - 'pseudoClass': function (t) { + 'pseudoClass': function pseudoClass(t) { return ':' + _composite(t.content); }, - 'pseudoElement': function (t) { + 'pseudoElement': function pseudoElement(t) { return '::' + _composite(t.content); }, - 'singlelineComment': function (t) { + 'singlelineComment': function singlelineComment(t) { return '/' + '/' + t.content; }, - 'uri': function (t) { + 'universalSelector': function universalSelector(t) { + return _composite(t.content) + '*'; + }, + 'uri': function uri(t) { return 'url(' + _composite(t.content) + ')'; }, - 'variable': function (t) { + 'variable': function variable(t) { return '@' + _composite(t.content); }, - 'variablesList': function (t) { + 'variablesList': function variablesList(t) { return _composite(t.content) + '...'; } }; @@ -528,8 +541,6 @@ /* 5 */ /***/ function(module, exports) { - // jscs:disable maximumLineLength - 'use strict'; module.exports = function stringify(tree) { @@ -549,72 +560,88 @@ var s = ''; i = i || 0; - for (; i < t.length; i++) s += _t(t[i]); - return s; + for (; i < t.length; i++) { + s += _t(t[i]); + }return s; } var _unique = { - 'arguments': function (t) { + 'arguments': function _arguments(t) { return '(' + _composite(t.content) + ')'; }, - 'atkeyword': function (t) { + 'atkeyword': function atkeyword(t) { return '@' + _composite(t.content); }, - 'attributeSelector': function (t) { + 'attributeSelector': function attributeSelector(t) { return '[' + _composite(t.content) + ']'; }, - 'block': function (t) { + 'block': function block(t) { return _composite(t.content); }, - 'brackets': function (t) { + 'brackets': function brackets(t) { return '[' + _composite(t.content) + ']'; }, - 'class': function (t) { + 'class': function _class(t) { return '.' + _composite(t.content); }, - 'color': function (t) { + 'color': function color(t) { return '#' + t.content; }, - 'expression': function (t) { + 'expression': function expression(t) { return 'expression(' + t.content + ')'; }, - 'id': function (t) { + 'id': function id(t) { return '#' + _composite(t.content); }, - 'interpolation': function (t) { + 'interpolation': function interpolation(t) { return '#{' + _composite(t.content) + '}'; }, - 'multilineComment': function (t) { - return '/*' + t.content; + 'multilineComment': function multilineComment(t) { + var lines = t.content.split('\n'); + var close = ''; + + if (lines.length > 1) { + var lastLine = lines[lines.length - 1]; + if (lastLine.length < t.end.column) { + close = '*/'; + } + } else if (t.content.length + 4 === t.end.column - t.start.column + 1) { + close = '*/'; + } + + return '/*' + t.content + close; }, - 'nthSelector': function (t) { + 'nthSelector': function nthSelector(t) { return ':' + _t(t.content[0]) + '(' + _composite(t.content.slice(1)) + ')'; }, - 'parentheses': function (t) { + 'parentheses': function parentheses(t) { return '(' + _composite(t.content) + ')'; }, - 'percentage': function (t) { + 'percentage': function percentage(t) { return _composite(t.content) + '%'; }, - 'placeholder': function (t) { + 'placeholder': function placeholder(t) { return '%' + _composite(t.content); }, - 'pseudoClass': function (t) { + 'pseudoClass': function pseudoClass(t) { return ':' + _composite(t.content); }, - 'pseudoElement': function (t) { + 'pseudoElement': function pseudoElement(t) { return '::' + _composite(t.content); }, - 'singlelineComment': function (t) { + 'singlelineComment': function singlelineComment(t) { return '/' + '/' + t.content; }, - 'uri': function (t) { + 'universalSelector': function universalSelector(t) { + return _composite(t.content) + '*'; + }, + 'uri': function uri(t) { return 'url(' + _composite(t.content) + ')'; }, - 'variable': function (t) { + 'variable': function variable(t) { return '$' + _composite(t.content); }, - 'variablesList': function (t) { + 'variablesList': function variablesList(t) { return _composite(t.content) + '...'; } }; @@ -626,8 +653,6 @@ /* 6 */ /***/ function(module, exports) { - // jscs:disable maximumLineLength - 'use strict'; module.exports = function stringify(tree) { @@ -647,72 +672,76 @@ var s = ''; i = i || 0; - for (; i < t.length; i++) s += _t(t[i]); - return s; + for (; i < t.length; i++) { + s += _t(t[i]); + }return s; } var _unique = { - 'arguments': function (t) { + 'arguments': function _arguments(t) { return '(' + _composite(t.content) + ')'; }, - 'atkeyword': function (t) { + 'atkeyword': function atkeyword(t) { return '@' + _composite(t.content); }, - 'attributeSelector': function (t) { + 'attributeSelector': function attributeSelector(t) { return '[' + _composite(t.content) + ']'; }, - 'block': function (t) { + 'block': function block(t) { return '{' + _composite(t.content) + '}'; }, - 'brackets': function (t) { + 'brackets': function brackets(t) { return '[' + _composite(t.content) + ']'; }, - 'class': function (t) { + 'class': function _class(t) { return '.' + _composite(t.content); }, - 'color': function (t) { + 'color': function color(t) { return '#' + t.content; }, - 'expression': function (t) { + 'expression': function expression(t) { return 'expression(' + t.content + ')'; }, - 'id': function (t) { + 'id': function id(t) { return '#' + _composite(t.content); }, - 'interpolation': function (t) { + 'interpolation': function interpolation(t) { return '#{' + _composite(t.content) + '}'; }, - 'multilineComment': function (t) { + 'multilineComment': function multilineComment(t) { return '/*' + t.content + '*/'; }, - 'nthSelector': function (t) { + 'nthSelector': function nthSelector(t) { return ':' + _t(t.content[0]) + '(' + _composite(t.content.slice(1)) + ')'; }, - 'parentheses': function (t) { + 'parentheses': function parentheses(t) { return '(' + _composite(t.content) + ')'; }, - 'percentage': function (t) { + 'percentage': function percentage(t) { return _composite(t.content) + '%'; }, - 'placeholder': function (t) { + 'placeholder': function placeholder(t) { return '%' + _composite(t.content); }, - 'pseudoClass': function (t) { + 'pseudoClass': function pseudoClass(t) { return ':' + _composite(t.content); }, - 'pseudoElement': function (t) { + 'pseudoElement': function pseudoElement(t) { return '::' + _composite(t.content); }, - 'singlelineComment': function (t) { + 'singlelineComment': function singlelineComment(t) { return '/' + '/' + t.content; }, - 'uri': function (t) { + 'universalSelector': function universalSelector(t) { + return _composite(t.content) + '*'; + }, + 'uri': function uri(t) { return 'url(' + _composite(t.content) + ')'; }, - 'variable': function (t) { + 'variable': function variable(t) { return '$' + _composite(t.content); }, - 'variablesList': function (t) { + 'variablesList': function variablesList(t) { return _composite(t.content) + '...'; } }; @@ -739,19 +768,14 @@ * @return {Object} AST */ function parser(css, options) { - if (typeof css !== 'string') throw new Error('Please, pass a string to parse');else if (!css) return __webpack_require__(16)(); + if (typeof css !== 'string') throw new Error('Please, pass a string to parse');else if (!css) return __webpack_require__(21)(); var syntax = options && options.syntax || 'css'; var context = options && options.context || 'stylesheet'; var tabSize = options && options.tabSize; if (!isInteger(tabSize) || tabSize < 1) tabSize = 1; - var syntaxParser = undefined; - if (syntaxes[syntax]) { - syntaxParser = syntaxes[syntax]; - } else { - syntaxParser = syntaxes; - } + var syntaxParser = syntaxes[syntax]; if (!syntaxParser) { var message = 'Syntax "' + syntax + '" is not supported yet, sorry'; @@ -796,7 +820,7 @@ this.css_ = css; } - ParsingError.prototype = Object.defineProperties({ + ParsingError.prototype = { /** * @type {String} * @private @@ -824,60 +848,52 @@ version: parserPackage.version, /** + * @type {String} + */ + get context() { + var LINES_AROUND = 2; + + var result = []; + var currentLineNumber = this.line; + var start = currentLineNumber - 1 - LINES_AROUND; + var end = currentLineNumber + LINES_AROUND; + var lines = this.css_.split(/\r\n|\r|\n/); + + for (var i = start; i < end; i++) { + var line = lines[i]; + if (!line) continue; + var ln = i + 1; + var mark = ln === currentLineNumber ? '*' : ' '; + result.push(ln + mark + '| ' + line); + } + + return result.join('\n'); + }, + + /** + * @type {String} + */ + get message() { + if (this.customMessage_) { + return this.customMessage_; + } else { + var message = 'Please check validity of the block'; + if (typeof this.line === 'number') message += ' starting from line #' + this.line; + return message; + } + }, + + set message(message) { + this.customMessage_ = message; + }, + + /** * @return {String} */ - toString: function () { + toString: function toString() { return [this.name + ': ' + this.message, '', this.context, '', 'Syntax: ' + this.syntax, 'Gonzales PE version: ' + this.version].join('\n'); } - }, { - context: { /** - * @type {String} - */ - - get: function () { - var LINES_AROUND = 2; - - var result = []; - var currentLineNumber = this.line; - var start = currentLineNumber - 1 - LINES_AROUND; - var end = currentLineNumber + LINES_AROUND; - var lines = this.css_.split(/\r\n|\r|\n/); - - for (var i = start; i < end; i++) { - var line = lines[i]; - if (!line) continue; - var ln = i + 1; - var mark = ln === currentLineNumber ? '*' : ' '; - result.push(ln + mark + '| ' + line); - } - - return result.join('\n'); - }, - configurable: true, - enumerable: true - }, - message: { - - /** - * @type {String} - */ - - get: function () { - if (this.customMessage_) { - return this.customMessage_; - } else { - var message = 'Please check validity of the block'; - if (typeof this.line === 'number') message += ' starting from line #' + this.line; - return message; - } - }, - set: function (message) { - this.customMessage_ = message; - }, - configurable: true, - enumerable: true - } - }); + }; module.exports = ParsingError; @@ -888,7 +904,7 @@ module.exports = { "name": "gonzales-pe", "description": "Gonzales Preprocessor Edition (fast CSS parser)", - "version": "3.3.1", + "version": "4.0.3", "homepage": "http://github.com/tonyganch/gonzales-pe", "bugs": "http://github.com/tonyganch/gonzales-pe/issues", "license": "MIT", @@ -906,10 +922,11 @@ "autofix-tests": "bash ./scripts/build.sh && bash ./scripts/autofix-tests.sh", "build": "bash ./scripts/build.sh", "init": "bash ./scripts/init.sh", + "lint": "bash ./scripts/lint.sh", "log": "bash ./scripts/log.sh", "prepublish": "bash ./scripts/prepublish.sh", "postpublish": "bash ./scripts/postpublish.sh", - "test": "bash ./scripts/build.sh && bash ./scripts/test.sh", + "test": "bash ./scripts/test.sh", "watch": "bash ./scripts/watch.sh" }, "bin": { @@ -919,13 +936,18 @@ "minimist": "1.1.x" }, "devDependencies": { - "babel-loader": "^5.3.2", + "babel-core": "^6.18.2", + "babel-loader": "^6.2.7", + "babel-plugin-add-module-exports": "^0.2.1", + "babel-preset-es2015": "^6.18.0", "coffee-script": "~1.7.1", + "eslint": "^3.0.0", "jscs": "2.1.0", "jshint": "2.8.0", "json-loader": "^0.5.3", "mocha": "2.2.x", - "webpack": "^1.12.2" + "webpack": "^1.12.2", + "webpack-closure-compiler": "^2.0.2" }, "engines": { "node": ">=0.6.0" @@ -938,14 +960,10 @@ 'use strict'; - exports.__esModule = true; - exports['default'] = { - mark: __webpack_require__(11), - parse: __webpack_require__(13), - stringify: __webpack_require__(6), - tokenizer: __webpack_require__(15) + module.exports = { + css: __webpack_require__(11), + scss: __webpack_require__(17) }; - module.exports = exports['default']; /***/ }, /* 11 */ @@ -953,125 +971,148 @@ 'use strict'; - var TokenType = __webpack_require__(12); - - module.exports = (function () { - /** - * Mark whitespaces and comments - */ - function markSC(tokens) { - var tokensLength = tokens.length; - var ws = -1; // Flag for whitespaces - var sc = -1; // Flag for whitespaces and comments - var t = undefined; // Current token - - // For every token in the token list, mark spaces and line breaks - // as spaces (set both `ws` and `sc` flags). Mark multiline comments - // with `sc` flag. - // If there are several spaces or tabs or line breaks or multiline - // comments in a row, group them: take the last one's index number - // and save it to the first token in the group as a reference: - // e.g., `ws_last = 7` for a group of whitespaces or `sc_last = 9` - // for a group of whitespaces and comments. - for (var i = 0; i < tokensLength; i++) { - t = tokens[i]; - switch (t.type) { - case TokenType.Space: - case TokenType.Tab: - case TokenType.Newline: - t.ws = true; - t.sc = true; - - if (ws === -1) ws = i; - if (sc === -1) sc = i; - - break; - case TokenType.CommentML: - case TokenType.CommentSL: - if (ws !== -1) { - tokens[ws].ws_last = i - 1; - ws = -1; - } - - t.sc = true; - - break; - default: - if (ws !== -1) { - tokens[ws].ws_last = i - 1; - ws = -1; - } - - if (sc !== -1) { - tokens[sc].sc_last = i - 1; - sc = -1; - } - } - } - - if (ws !== -1) tokens[ws].ws_last = i - 1; - if (sc !== -1) tokens[sc].sc_last = i - 1; - } - - /** - * Pair brackets - */ - function markBrackets(tokens) { - var tokensLength = tokens.length; - var ps = []; // Parentheses - var sbs = []; // Square brackets - var cbs = []; // Curly brackets - var t = undefined; // Current token - - // For every token in the token list, if we meet an opening (left) - // bracket, push its index number to a corresponding array. - // If we then meet a closing (right) bracket, look at the corresponding - // array. If there are any elements (records about previously met - // left brackets), take a token of the last left bracket (take - // the last index number from the array and find a token with - // this index number) and save right bracket's index as a reference: - for (var i = 0; i < tokensLength; i++) { - t = tokens[i]; - switch (t.type) { - case TokenType.LeftParenthesis: - ps.push(i); - break; - case TokenType.RightParenthesis: - if (ps.length) { - t.left = ps.pop(); - tokens[t.left].right = i; - } - break; - case TokenType.LeftSquareBracket: - sbs.push(i); - break; - case TokenType.RightSquareBracket: - if (sbs.length) { - t.left = sbs.pop(); - tokens[t.left].right = i; - } - break; - case TokenType.LeftCurlyBracket: - cbs.push(i); - break; - case TokenType.RightCurlyBracket: - if (cbs.length) { - t.left = cbs.pop(); - tokens[t.left].right = i; - } - break; - } - } - } - - return function (tokens) { - markBrackets(tokens); - markSC(tokens); - }; - })(); + exports.__esModule = true; + exports.default = { + mark: __webpack_require__(12), + parse: __webpack_require__(14), + stringify: __webpack_require__(3), + tokenizer: __webpack_require__(16) + }; + module.exports = exports['default']; /***/ }, /* 12 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var TokenType = __webpack_require__(13); + + /** + * Mark whitespaces and comments + * @param {Array} tokens + */ + function markSpacesAndComments(tokens) { + var tokensLength = tokens.length; + var spaces = [-1, -1]; + var type; // Current token's type + + // For every token in the token list, mark spaces and line breaks + // as spaces (set both `ws` and `sc` flags). Mark multiline comments + // with `sc` flag. + // If there are several spaces or tabs or line breaks or multiline + // comments in a row, group them: take the last one's index number + // and save it to the first token in the group as a reference: + // e.g., `ws_last = 7` for a group of whitespaces or `sc_last = 9` + // for a group of whitespaces and comments. + for (var i = 0; i < tokensLength; i++) { + type = tokens[i].type; + + if (type === TokenType.Space || type === TokenType.Tab || type === TokenType.Newline) { + markSpace(tokens, i, spaces); + } else if (type === TokenType.CommentML) { + markComment(tokens, i, spaces); + } else { + markEndOfSpacesAndComments(tokens, i, spaces); + } + } + + markEndOfSpacesAndComments(tokens, i, spaces); + } + + function markSpace(tokens, i, spaces) { + var token = tokens[i]; + token.ws = true; + token.sc = true; + + if (spaces[0] === -1) spaces[0] = i; + if (spaces[1] === -1) spaces[1] = i; + } + + function markComment(tokens, i, spaces) { + var ws = spaces[0]; + tokens[i].sc = true; + + if (ws !== -1) { + tokens[ws].ws_last = i - 1; + spaces[0] = -1; + } + } + + function markEndOfSpacesAndComments(tokens, i, spaces) { + var ws = spaces[0]; + var sc = spaces[1]; + if (ws !== -1) { + tokens[ws].ws_last = i - 1; + spaces[0] = -1; + } + if (sc !== -1) { + tokens[sc].sc_last = i - 1; + spaces[1] = -1; + } + } + + /** + * Pair brackets + * @param {Array} tokens + */ + function markBrackets(tokens) { + var tokensLength = tokens.length; + var ps = []; // Parentheses + var sbs = []; // Square brackets + var cbs = []; // Curly brackets + var t = void 0; // Current token + + // For every token in the token list, if we meet an opening (left) + // bracket, push its index number to a corresponding array. + // If we then meet a closing (right) bracket, look at the corresponding + // array. If there are any elements (records about previously met + // left brackets), take a token of the last left bracket (take + // the last index number from the array and find a token with + // this index number) and save right bracket's index as a reference: + for (var i = 0; i < tokensLength; i++) { + t = tokens[i]; + var type = t.type; + + if (type === TokenType.LeftParenthesis) { + ps.push(i); + } else if (type === TokenType.RightParenthesis) { + if (ps.length) { + t.left = ps.pop(); + tokens[t.left].right = i; + } + } else if (type === TokenType.LeftSquareBracket) { + sbs.push(i); + } else if (type === TokenType.RightSquareBracket) { + if (sbs.length) { + t.left = sbs.pop(); + tokens[t.left].right = i; + } + } else if (type === TokenType.LeftCurlyBracket) { + cbs.push(i); + } else if (type === TokenType.RightCurlyBracket) { + if (cbs.length) { + t.left = cbs.pop(); + tokens[t.left].right = i; + } + } + } + } + + /** + * @param {Array} tokens + */ + function markTokens(tokens) { + // Mark paired brackets: + markBrackets(tokens); + // Mark whitespaces and comments: + markSpacesAndComments(tokens); + } + + module.exports = markTokens; + +/***/ }, +/* 13 */ /***/ function(module, exports) { // jscs:disable @@ -1127,650 +1168,3399 @@ }; /***/ }, -/* 13 */ +/* 14 */ /***/ function(module, exports, __webpack_require__) { - // jscs:disable maximumLineLength - 'use strict';var Node=__webpack_require__(1);var NodeType=__webpack_require__(14);var TokenType=__webpack_require__(12);var tokens=undefined;var tokensLength=undefined;var pos=undefined;var contexts={'arguments':function(){return checkArguments(pos) && getArguments();},'atkeyword':function(){return checkAtkeyword(pos) && getAtkeyword();},'atrule':function(){return checkAtrule(pos) && getAtrule();},'block':function(){return checkBlock(pos) && getBlock();},'brackets':function(){return checkBrackets(pos) && getBrackets();},'class':function(){return checkClass(pos) && getClass();},'combinator':function(){return checkCombinator(pos) && getCombinator();},'commentML':function(){return checkCommentML(pos) && getCommentML();},'commentSL':function(){return checkCommentSL(pos) && getCommentSL();},'condition':function(){return checkCondition(pos) && getCondition();},'conditionalStatement':function(){return checkConditionalStatement(pos) && getConditionalStatement();},'declaration':function(){return checkDeclaration(pos) && getDeclaration();},'declDelim':function(){return checkDeclDelim(pos) && getDeclDelim();},'default':function(){return checkDefault(pos) && getDefault();},'delim':function(){return checkDelim(pos) && getDelim();},'dimension':function(){return checkDimension(pos) && getDimension();},'expression':function(){return checkExpression(pos) && getExpression();},'extend':function(){return checkExtend(pos) && getExtend();},'function':function(){return checkFunction(pos) && getFunction();},'global':function(){return checkGlobal(pos) && getGlobal();},'ident':function(){return checkIdent(pos) && getIdent();},'important':function(){return checkImportant(pos) && getImportant();},'include':function(){return checkInclude(pos) && getInclude();},'interpolation':function(){return checkInterpolation(pos) && getInterpolation();},'loop':function(){return checkLoop(pos) && getLoop();},'mixin':function(){return checkMixin(pos) && getMixin();},'namespace':function(){return checkNamespace(pos) && getNamespace();},'number':function(){return checkNumber(pos) && getNumber();},'operator':function(){return checkOperator(pos) && getOperator();},'optional':function(){return checkOptional(pos) && getOptional();},'parentheses':function(){return checkParentheses(pos) && getParentheses();},'parentselector':function(){return checkParentSelector(pos) && getParentSelector();},'percentage':function(){return checkPercentage(pos) && getPercentage();},'placeholder':function(){return checkPlaceholder(pos) && getPlaceholder();},'progid':function(){return checkProgid(pos) && getProgid();},'property':function(){return checkProperty(pos) && getProperty();},'propertyDelim':function(){return checkPropertyDelim(pos) && getPropertyDelim();},'pseudoc':function(){return checkPseudoc(pos) && getPseudoc();},'pseudoe':function(){return checkPseudoe(pos) && getPseudoe();},'ruleset':function(){return checkRuleset(pos) && getRuleset();},'s':function(){return checkS(pos) && getS();},'selector':function(){return checkSelector(pos) && getSelector();},'shash':function(){return checkShash(pos) && getShash();},'string':function(){return checkString(pos) && getString();},'stylesheet':function(){return checkStylesheet(pos) && getStylesheet();},'unary':function(){return checkUnary(pos) && getUnary();},'uri':function(){return checkUri(pos) && getUri();},'value':function(){return checkValue(pos) && getValue();},'variable':function(){return checkVariable(pos) && getVariable();},'variableslist':function(){return checkVariablesList(pos) && getVariablesList();},'vhash':function(){return checkVhash(pos) && getVhash();}}; /** - * Stop parsing and display error + 'use strict'; + + var Node = __webpack_require__(1); + var NodeType = __webpack_require__(15); + var TokenType = __webpack_require__(13); + + /** + * @type {Array} + */ + var tokens; + + /** + * @type {Number} + */ + var tokensLength; + + /** + * @type {Number} + */ + var pos; + + var contexts = { + 'atkeyword': function atkeyword() { + return checkAtkeyword(pos) && getAtkeyword(); + }, + 'atrule': function atrule() { + return checkAtrule(pos) && getAtrule(); + }, + 'block': function block() { + return checkBlock(pos) && getBlock(); + }, + 'brackets': function brackets() { + return checkBrackets(pos) && getBrackets(); + }, + 'class': function _class() { + return checkClass(pos) && getClass(); + }, + 'combinator': function combinator() { + return checkCombinator(pos) && getCombinator(); + }, + 'commentML': function commentML() { + return checkCommentML(pos) && getCommentML(); + }, + 'declaration': function declaration() { + return checkDeclaration(pos) && getDeclaration(); + }, + 'declDelim': function declDelim() { + return checkDeclDelim(pos) && getDeclDelim(); + }, + 'delim': function delim() { + return checkDelim(pos) && getDelim(); + }, + 'dimension': function dimension() { + return checkDimension(pos) && getDimension(); + }, + 'expression': function expression() { + return checkExpression(pos) && getExpression(); + }, + 'function': function _function() { + return checkFunction(pos) && getFunction(); + }, + 'ident': function ident() { + return checkIdent(pos) && getIdent(); + }, + 'important': function important() { + return checkImportant(pos) && getImportant(); + }, + 'namespace': function namespace() { + return checkNamespace(pos) && getNamespace(); + }, + 'number': function number() { + return checkNumber(pos) && getNumber(); + }, + 'operator': function operator() { + return checkOperator(pos) && getOperator(); + }, + 'parentheses': function parentheses() { + return checkParentheses(pos) && getParentheses(); + }, + 'percentage': function percentage() { + return checkPercentage(pos) && getPercentage(); + }, + 'progid': function progid() { + return checkProgid(pos) && getProgid(); + }, + 'property': function property() { + return checkProperty(pos) && getProperty(); + }, + 'propertyDelim': function propertyDelim() { + return checkPropertyDelim(pos) && getPropertyDelim(); + }, + 'pseudoc': function pseudoc() { + return checkPseudoc(pos) && getPseudoc(); + }, + 'pseudoe': function pseudoe() { + return checkPseudoe(pos) && getPseudoe(); + }, + 'ruleset': function ruleset() { + return checkRuleset(pos) && getRuleset(); + }, + 's': function s() { + return checkS(pos) && getS(); + }, + 'selector': function selector() { + return checkSelector(pos) && getSelector(); + }, + 'shash': function shash() { + return checkShash(pos) && getShash(); + }, + 'string': function string() { + return checkString(pos) && getString(); + }, + 'stylesheet': function stylesheet() { + return checkStylesheet(pos) && getStylesheet(); + }, + 'unary': function unary() { + return checkUnary(pos) && getUnary(); + }, + 'unicodeRange': function unicodeRange() { + return checkUnicodeRange(pos) && getUnicodeRange(); + }, + 'universalSelector': function universalSelector() { + return checkUniversalSelector(pos) && getUniversalSelector(); + }, + 'urange': function urange() { + return checkUrange(pos) && getUrange(); + }, + 'uri': function uri() { + return checkUri(pos) && getUri(); + }, + 'value': function value() { + return checkValue(pos) && getValue(); + }, + 'vhash': function vhash() { + return checkVhash(pos) && getVhash(); + } + }; + + /** + * Stop parsing and display error. * @param {Number=} i Token's index number - */function throwError(i){var ln=i?tokens[i].ln:tokens[pos].ln;throw {line:ln,syntax:'scss'};} /** + */ + function throwError(i) { + var ln = tokens[i].ln; + + throw { line: ln, syntax: 'css' }; + } + + /** * @param {Object} exclude * @param {Number} i Token's index number - * @returns {Number} - */function checkExcluding(exclude,i){var start=i;while(i < tokensLength) {if(exclude[tokens[i++].type])break;}return i - start - 2;} /** + * @return {Number} + */ + function checkExcluding(exclude, i) { + var start = i; + + while (i < tokensLength) { + if (exclude[tokens[i++].type]) break; + } + + return i - start - 2; + } + + /** * @param {Number} start * @param {Number} finish - * @returns {String} - */function joinValues(start,finish){var s='';for(var i=start;i < finish + 1;i++) {s += tokens[i].value;}return s;} /** + * @return {String} + */ + function joinValues(start, finish) { + var s = ''; + + for (var i = start; i < finish + 1; i++) { + s += tokens[i].value; + } + + return s; + } + + /** * @param {Number} start * @param {Number} num - * @returns {String} - */function joinValues2(start,num){if(start + num - 1 >= tokensLength)return;var s='';for(var i=0;i < num;i++) {s += tokens[start + i].value;}return s;}function getLastPosition(content,line,column,colOffset){return typeof content === 'string'?getLastPositionForString(content,line,column,colOffset):getLastPositionForArray(content,line,column,colOffset);}function getLastPositionForString(content,line,column,colOffset){var position=[];if(!content){position = [line,column];if(colOffset)position[1] += colOffset - 1;return position;}var lastLinebreak=content.lastIndexOf('\n');var endsWithLinebreak=lastLinebreak === content.length - 1;var splitContent=content.split('\n');var linebreaksCount=splitContent.length - 1;var prevLinebreak=linebreaksCount === 0 || linebreaksCount === 1?-1:content.length - splitContent[linebreaksCount - 1].length - 2; // Line: - var offset=endsWithLinebreak?linebreaksCount - 1:linebreaksCount;position[0] = line + offset; // Column: - if(endsWithLinebreak){offset = prevLinebreak !== -1?content.length - prevLinebreak:content.length - 1;}else {offset = linebreaksCount !== 0?content.length - lastLinebreak - column - 1:content.length - 1;}position[1] = column + offset;if(!colOffset)return position;if(endsWithLinebreak){position[0]++;position[1] = colOffset;}else {position[1] += colOffset;}return position;}function getLastPositionForArray(content,line,column,colOffset){var position;if(content.length === 0){position = [line,column];}else {var c=content[content.length - 1];if(c.hasOwnProperty('end')){position = [c.end.line,c.end.column];}else {position = getLastPosition(c.content,line,column);}}if(!colOffset)return position;if(tokens[pos - 1].type !== 'Newline'){position[1] += colOffset;}else {position[0]++;position[1] = 1;}return position;}function newNode(type,content,line,column,end){if(!end)end = getLastPosition(content,line,column);return new Node({type:type,content:content,start:{line:line,column:column},end:{line:end[0],column:end[1]},syntax:'scss'});} /** + * @return {String} + */ + function joinValues2(start, num) { + if (start + num - 1 >= tokensLength) return; + + var s = ''; + + for (var i = 0; i < num; i++) { + s += tokens[start + i].value; + } + + return s; + } + + function getLastPosition(content, line, column, colOffset) { + return typeof content === 'string' ? getLastPositionForString(content, line, column, colOffset) : getLastPositionForArray(content, line, column, colOffset); + } + + function getLastPositionForString(content, line, column, colOffset) { + var position = []; + + if (!content) { + position = [line, column]; + if (colOffset) position[1] += colOffset - 1; + return position; + } + + var lastLinebreak = content.lastIndexOf('\n'); + var endsWithLinebreak = lastLinebreak === content.length - 1; + var splitContent = content.split('\n'); + var linebreaksCount = splitContent.length - 1; + var prevLinebreak = linebreaksCount === 0 || linebreaksCount === 1 ? -1 : content.length - splitContent[linebreaksCount - 1].length - 2; + + // Line: + var offset = endsWithLinebreak ? linebreaksCount - 1 : linebreaksCount; + position[0] = line + offset; + + // Column: + if (endsWithLinebreak) { + offset = prevLinebreak !== -1 ? content.length - prevLinebreak : content.length - 1; + } else { + offset = linebreaksCount !== 0 ? content.length - lastLinebreak - column - 1 : content.length - 1; + } + position[1] = column + offset; + + if (!colOffset) return position; + + if (endsWithLinebreak) { + position[0]++; + position[1] = colOffset; + } else { + position[1] += colOffset; + } + + return position; + } + + function getLastPositionForArray(content, line, column, colOffset) { + var position; + + if (content.length === 0) { + position = [line, column]; + } else { + var c = content[content.length - 1]; + if (c.hasOwnProperty('end')) { + position = [c.end.line, c.end.column]; + } else { + position = getLastPosition(c.content, line, column); + } + } + + if (!colOffset) return position; + + if (tokens[pos - 1] && tokens[pos - 1].type !== 'Newline') { + position[1] += colOffset; + } else { + position[0]++; + position[1] = 1; + } + + return position; + } + + function newNode(type, content, line, column, end) { + if (!end) end = getLastPosition(content, line, column); + return new Node({ + type: type, + content: content, + start: { + line: line, + column: column + }, + end: { + line: end[0], + column: end[1] + }, + syntax: 'css' + }); + } + + /** * @param {Number} i Token's index number - * @returns {Number} - */function checkAny(i){return checkBrackets(i) || checkParentheses(i) || checkString(i) || checkVariablesList(i) || checkVariable(i) || checkPlaceholder(i) || checkPercentage(i) || checkDimension(i) || checkNumber(i) || checkUri(i) || checkExpression(i) || checkFunction(i) || checkInterpolation(i) || checkIdent(i) || checkClass(i) || checkUnary(i);} /** - * @returns {Array} - */function getAny(){if(checkBrackets(pos))return getBrackets();else if(checkParentheses(pos))return getParentheses();else if(checkString(pos))return getString();else if(checkVariablesList(pos))return getVariablesList();else if(checkVariable(pos))return getVariable();else if(checkPlaceholder(pos))return getPlaceholder();else if(checkPercentage(pos))return getPercentage();else if(checkDimension(pos))return getDimension();else if(checkNumber(pos))return getNumber();else if(checkUri(pos))return getUri();else if(checkExpression(pos))return getExpression();else if(checkFunction(pos))return getFunction();else if(checkInterpolation(pos))return getInterpolation();else if(checkIdent(pos))return getIdent();else if(checkClass(pos))return getClass();else if(checkUnary(pos))return getUnary();} /** - * Check if token is part of mixin's arguments. - * @param {Number} i Token's index number - * @returns {Number} Length of arguments - */function checkArguments(i){var start=i;var l=undefined;if(i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis)return 0;i++;while(i < tokens[start].right) {if(l = checkArgument(i))i += l;else return 0;}return tokens[start].right - start + 1;} /** - * Check if token is valid to be part of arguments list - * @param {Number} i Token's index number - * @returns {Number} Length of argument - */function checkArgument(i){return checkBrackets(i) || checkParentheses(i) || checkDeclaration(i) || checkFunction(i) || checkVariablesList(i) || checkVariable(i) || checkSC(i) || checkDelim(i) || checkDeclDelim(i) || checkString(i) || checkPercentage(i) || checkDimension(i) || checkNumber(i) || checkUri(i) || checkInterpolation(i) || checkIdent(i) || checkVhash(i) || checkOperator(i) || checkUnary(i);} /** - * @returns {Array} Node that is part of arguments list - */function getArgument(){if(checkBrackets(pos))return getBrackets();else if(checkParentheses(pos))return getParentheses();else if(checkDeclaration(pos))return getDeclaration();else if(checkFunction(pos))return getFunction();else if(checkVariablesList(pos))return getVariablesList();else if(checkVariable(pos))return getVariable();else if(checkSC(pos))return getSC();else if(checkDelim(pos))return getDelim();else if(checkDeclDelim(pos))return getDeclDelim();else if(checkString(pos))return getString();else if(checkPercentage(pos))return getPercentage();else if(checkDimension(pos))return getDimension();else if(checkNumber(pos))return getNumber();else if(checkUri(pos))return getUri();else if(checkInterpolation(pos))return getInterpolation();else if(checkIdent(pos))return getIdent();else if(checkVhash(pos))return getVhash();else if(checkOperator(pos))return getOperator();else if(checkUnary(pos))return getUnary();} /** + * @return {Number} + */ + function checkAny(i) { + var l; + + if (l = checkBrackets(i)) tokens[i].any_child = 1;else if (l = checkParentheses(i)) tokens[i].any_child = 2;else if (l = checkString(i)) tokens[i].any_child = 3;else if (l = checkPercentage(i)) tokens[i].any_child = 4;else if (l = checkDimension(i)) tokens[i].any_child = 5;else if (l = checkUnicodeRange(i)) tokens[i].any_child = 13;else if (l = checkNumber(i)) tokens[i].any_child = 6;else if (l = checkUri(i)) tokens[i].any_child = 7;else if (l = checkExpression(i)) tokens[i].any_child = 8;else if (l = checkFunction(i)) tokens[i].any_child = 9;else if (l = checkIdent(i)) tokens[i].any_child = 10;else if (l = checkClass(i)) tokens[i].any_child = 11;else if (l = checkUnary(i)) tokens[i].any_child = 12; + + return l; + } + + /** + * @return {Node} + */ + function getAny() { + var childType = tokens[pos].any_child; + + if (childType === 1) return getBrackets();else if (childType === 2) return getParentheses();else if (childType === 3) return getString();else if (childType === 4) return getPercentage();else if (childType === 5) return getDimension();else if (childType === 13) return getUnicodeRange();else if (childType === 6) return getNumber();else if (childType === 7) return getUri();else if (childType === 8) return getExpression();else if (childType === 9) return getFunction();else if (childType === 10) return getIdent();else if (childType === 11) return getClass();else if (childType === 12) return getUnary(); + } + + /** * Check if token is part of an @-word (e.g. `@import`, `@include`) * @param {Number} i Token's index number - * @returns {Number} - */function checkAtkeyword(i){var l; // Check that token is `@`: - if(i >= tokensLength || tokens[i++].type !== TokenType.CommercialAt)return 0;return (l = checkIdentOrInterpolation(i))?l + 1:0;} /** + * @return {Number} + */ + function checkAtkeyword(i) { + var l; + + // Check that token is `@`: + if (i >= tokensLength || tokens[i++].type !== TokenType.CommercialAt) return 0; + + return (l = checkIdent(i)) ? l + 1 : 0; + } + + /** * Get node with @-word - * @returns {Array} `['atkeyword', ['ident', x]]` where `x` is - * an identifier without - * `@` (e.g. `import`, `include`) - */function getAtkeyword(){var startPos=pos;var x=undefined;pos++;x = getIdentOrInterpolation();var token=tokens[startPos];return newNode(NodeType.AtkeywordType,x,token.ln,token.col);} /** + * @return {Node} + */ + function getAtkeyword() { + var type = NodeType.AtkeywordType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + pos++; + + content.push(getIdent()); + + return newNode(type, content, line, column); + } + + /** * Check if token is a part of an @-rule * @param {Number} i Token's index number - * @returns {Number} Length of @-rule - */function checkAtrule(i){var l;if(i >= tokensLength)return 0; // If token already has a record of being part of an @-rule, - // return the @-rule's length: - if(tokens[i].atrule_l !== undefined)return tokens[i].atrule_l; // If token is part of an @-rule, save the rule's type to token: - if(l = checkKeyframesRule(i))tokens[i].atrule_type = 4;else if(l = checkAtruler(i))tokens[i].atrule_type = 1; // @-rule with ruleset - else if(l = checkAtruleb(i))tokens[i].atrule_type = 2; // Block @-rule - else if(l = checkAtrules(i))tokens[i].atrule_type = 3; // Single-line @-rule - else return 0; // If token is part of an @-rule, save the rule's length to token: - tokens[i].atrule_l = l;return l;} /** + * @return {Number} Length of @-rule + */ + function checkAtrule(i) { + var l; + + if (i >= tokensLength) return 0; + + // If token already has a record of being part of an @-rule, + // return the @-rule's length: + if (tokens[i].atrule_l !== undefined) return tokens[i].atrule_l; + + // If token is part of an @-rule, save the rule's type to token. + // @keyframes: + if (l = checkKeyframesRule(i)) tokens[i].atrule_type = 4; + // @-rule with ruleset: + else if (l = checkAtruler(i)) tokens[i].atrule_type = 1; + // Block @-rule: + else if (l = checkAtruleb(i)) tokens[i].atrule_type = 2; + // Single-line @-rule: + else if (l = checkAtrules(i)) tokens[i].atrule_type = 3;else return 0; + + // If token is part of an @-rule, save the rule's length to token: + tokens[i].atrule_l = l; + + return l; + } + + /** * Get node with @-rule - * @returns {Array} - */function getAtrule(){switch(tokens[pos].atrule_type){case 1:return getAtruler(); // @-rule with ruleset - case 2:return getAtruleb(); // Block @-rule - case 3:return getAtrules(); // Single-line @-rule - case 4:return getKeyframesRule();}} /** + * @return {Node} + */ + function getAtrule() { + switch (tokens[pos].atrule_type) { + case 1: + return getAtruler(); // @-rule with ruleset + case 2: + return getAtruleb(); // Block @-rule + case 3: + return getAtrules(); // Single-line @-rule + case 4: + return getKeyframesRule(); + } + } + + /** * Check if token is part of a block @-rule * @param {Number} i Token's index number - * @returns {Number} Length of the @-rule - */function checkAtruleb(i){var start=i;var l=undefined;if(i >= tokensLength)return 0;if(l = checkAtkeyword(i))i += l;else return 0;if(l = checkTsets(i))i += l;if(l = checkBlock(i))i += l;else return 0;return i - start;} /** + * @return {Number} Length of the @-rule + */ + function checkAtruleb(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkAtkeyword(i)) i += l;else return 0; + + if (l = checkTsets(i)) i += l; + + if (l = checkBlock(i)) i += l;else return 0; + + return i - start; + } + + /** * Get node with a block @-rule - * @returns {Array} `['atruleb', ['atkeyword', x], y, ['block', z]]` - */function getAtruleb(){var startPos=pos;var x=undefined;x = [getAtkeyword()].concat(getTsets()).concat([getBlock()]);var token=tokens[startPos];return newNode(NodeType.AtruleType,x,token.ln,token.col);} /** + * @return {Node} + */ + function getAtruleb() { + var type = NodeType.AtruleType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = [getAtkeyword()].concat(getTsets()).concat([getBlock()]); + + return newNode(type, content, line, column); + } + + /** * Check if token is part of an @-rule with ruleset * @param {Number} i Token's index number - * @returns {Number} Length of the @-rule - */function checkAtruler(i){var start=i;var l=undefined;if(i >= tokensLength)return 0;if(l = checkAtkeyword(i))i += l;else return 0;if(l = checkTsets(i))i += l;if(i < tokensLength && tokens[i].type === TokenType.LeftCurlyBracket)i++;else return 0;if(l = checkAtrulers(i))i += l;if(i < tokensLength && tokens[i].type === TokenType.RightCurlyBracket)i++;else return 0;return i - start;} /** + * @return {Number} Length of the @-rule + */ + function checkAtruler(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkAtkeyword(i)) i += l;else return 0; + + if (l = checkTsets(i)) i += l; + + if (i < tokensLength && tokens[i].type === TokenType.LeftCurlyBracket) i++;else return 0; + + if (l = checkAtrulers(i)) i += l; + + if (i < tokensLength && tokens[i].type === TokenType.RightCurlyBracket) i++;else return 0; + + return i - start; + } + + /** * Get node with an @-rule with ruleset - * @returns {Array} ['atruler', ['atkeyword', x], y, z] - */function getAtruler(){var startPos=pos;var x=undefined;x = [getAtkeyword()].concat(getTsets());x.push(getAtrulers());var token=tokens[startPos];return newNode(NodeType.AtruleType,x,token.ln,token.col);} /** + * @return {Node} + */ + function getAtruler() { + var type = NodeType.AtruleType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = [getAtkeyword()]; + + content = content.concat(getTsets()); + + content.push(getAtrulers()); + + return newNode(type, content, line, column); + } + + /** * @param {Number} i Token's index number - * @returns {Number} - */function checkAtrulers(i){var start=i;var l=undefined;if(i >= tokensLength)return 0;while(l = checkRuleset(i) || checkAtrule(i) || checkSC(i)) {i += l;}if(i < tokensLength)tokens[i].atrulers_end = 1;return i - start;} /** - * @returns {Array} `['atrulers', x]` - */function getAtrulers(){var startPos=pos;var x=undefined;var token=tokens[startPos];var line=token.ln;var column=token.col;pos++;x = getSC();while(!tokens[pos].atrulers_end) {if(checkSC(pos))x = x.concat(getSC());else if(checkAtrule(pos))x.push(getAtrule());else if(checkRuleset(pos))x.push(getRuleset());}x = x.concat(getSC());var end=getLastPosition(x,line,column,1);pos++;return newNode(NodeType.BlockType,x,token.ln,token.col,end);} /** + * @return {Number} + */ + function checkAtrulers(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkSC(i)) i += l; + + while (i < tokensLength) { + if (l = checkSC(i)) tokens[i].atrulers_child = 1;else if (l = checkAtrule(i)) tokens[i].atrulers_child = 2;else if (l = checkRuleset(i)) tokens[i].atrulers_child = 3;else break; + i += l; + } + + tokens[i].atrulers_end = 1; + + if (l = checkSC(i)) i += l; + + return i - start; + } + + /** + * @return {Node} + */ + function getAtrulers() { + var type = NodeType.BlockType; + var token = tokens[pos++]; + var line = token.ln; + var column = token.col; + var content = getSC(); + + while (!tokens[pos].atrulers_end) { + var childType = tokens[pos].atrulers_child; + if (childType === 1) content = content.concat(getSC());else if (childType === 2) content.push(getAtrule());else if (childType === 3) content.push(getRuleset()); + } + + content = content.concat(getSC()); + + var end = getLastPosition(content, line, column, 1); + pos++; + + return newNode(type, content, line, column, end); + } + + /** * @param {Number} i Token's index number - * @returns {Number} - */function checkAtrules(i){var start=i;var l=undefined;if(i >= tokensLength)return 0;if(l = checkAtkeyword(i))i += l;else return 0;if(l = checkTsets(i))i += l;return i - start;} /** - * @returns {Array} `['atrules', ['atkeyword', x], y]` - */function getAtrules(){var startPos=pos;var x=undefined;x = [getAtkeyword()].concat(getTsets());var token=tokens[startPos];return newNode(NodeType.AtruleType,x,token.ln,token.col);} /** + * @return {Number} + */ + function checkAtrules(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkAtkeyword(i)) i += l;else return 0; + + if (l = checkTsets(i)) i += l; + + return i - start; + } + + /** + * @return {Node} + */ + function getAtrules() { + var type = NodeType.AtruleType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = [getAtkeyword()].concat(getTsets()); + + return newNode(type, content, line, column); + } + + /** * Check if token is part of a block (e.g. `{...}`). * @param {Number} i Token's index number - * @returns {Number} Length of the block - */function checkBlock(i){return i < tokensLength && tokens[i].type === TokenType.LeftCurlyBracket?tokens[i].right - i + 1:0;} /** + * @return {Number} Length of the block + */ + function checkBlock(i) { + return i < tokensLength && tokens[i].type === TokenType.LeftCurlyBracket ? tokens[i].right - i + 1 : 0; + } + + /** * Get node with a block - * @returns {Array} `['block', x]` - */function getBlock(){var startPos=pos;var end=tokens[pos].right;var x=[];var token=tokens[startPos];var line=token.ln;var column=token.col;pos++;while(pos < end) {if(checkBlockdecl(pos))x = x.concat(getBlockdecl());else throwError();}var end_=getLastPosition(x,line,column,1);pos = end + 1;return newNode(NodeType.BlockType,x,token.ln,token.col,end_);} /** + * @return {Node} + */ + function getBlock() { + var type = NodeType.BlockType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var end = tokens[pos++].right; + var content = []; + + while (pos < end) { + if (checkBlockdecl(pos)) content = content.concat(getBlockdecl());else throwError(pos); + } + + var end_ = getLastPosition(content, line, column, 1); + pos = end + 1; + + return newNode(type, content, line, column, end_); + } + + /** * Check if token is part of a declaration (property-value pair) * @param {Number} i Token's index number - * @returns {Number} Length of the declaration - */function checkBlockdecl(i){var l;if(i >= tokensLength)return 0;if(l = checkBlockdecl1(i))tokens[i].bd_type = 1;else if(l = checkBlockdecl2(i))tokens[i].bd_type = 2;else if(l = checkBlockdecl3(i))tokens[i].bd_type = 3;else if(l = checkBlockdecl4(i))tokens[i].bd_type = 4;else return 0;return l;} /** - * @returns {Array} - */function getBlockdecl(){switch(tokens[pos].bd_type){case 1:return getBlockdecl1();case 2:return getBlockdecl2();case 3:return getBlockdecl3();case 4:return getBlockdecl4();}} /** + * @return {Number} Length of the declaration + */ + function checkBlockdecl(i) { + var l; + + if (i >= tokensLength) return 0; + + if (l = checkBlockdecl1(i)) tokens[i].bd_type = 1;else if (l = checkBlockdecl2(i)) tokens[i].bd_type = 2;else if (l = checkBlockdecl3(i)) tokens[i].bd_type = 3;else if (l = checkBlockdecl4(i)) tokens[i].bd_type = 4;else return 0; + + return l; + } + + /** + * @return {Array} + */ + function getBlockdecl() { + switch (tokens[pos].bd_type) { + case 1: + return getBlockdecl1(); + case 2: + return getBlockdecl2(); + case 3: + return getBlockdecl3(); + case 4: + return getBlockdecl4(); + } + } + + /** * @param {Number} i Token's index number - * @returns {Number} - */function checkBlockdecl1(i){var start=i;var l=undefined;if(l = checkSC(i))i += l;if(l = checkConditionalStatement(i))tokens[i].bd_kind = 1;else if(l = checkInclude(i))tokens[i].bd_kind = 2;else if(l = checkExtend(i))tokens[i].bd_kind = 4;else if(l = checkLoop(i))tokens[i].bd_kind = 3;else if(l = checkAtrule(i))tokens[i].bd_kind = 6;else if(l = checkRuleset(i))tokens[i].bd_kind = 7;else if(l = checkDeclaration(i))tokens[i].bd_kind = 5;else return 0;i += l;if(i < tokensLength && (l = checkDeclDelim(i)))i += l;else return 0;if(l = checkSC(i))i += l;return i - start;} /** - * @returns {Array} - */function getBlockdecl1(){var sc=getSC();var x=undefined;switch(tokens[pos].bd_kind){case 1:x = getConditionalStatement();break;case 2:x = getInclude();break;case 3:x = getLoop();break;case 4:x = getExtend();break;case 5:x = getDeclaration();break;case 6:x = getAtrule();break;case 7:x = getRuleset();break;}return sc.concat([x]).concat([getDeclDelim()]).concat(getSC());} /** + * @return {Number} + */ + function checkBlockdecl1(i) { + var start = i; + var l = void 0; + + if (l = checkSC(i)) i += l; + + if (l = checkDeclaration(i)) tokens[i].bd_kind = 1;else if (l = checkAtrule(i)) tokens[i].bd_kind = 2;else return 0; + + i += l; + + if (l = checkSC(i)) i += l; + + if (i < tokensLength && (l = checkDeclDelim(i))) i += l;else return 0; + + if (l = checkSC(i)) i += l;else return 0; + + return i - start; + } + + /** + * @return {Array} + */ + function getBlockdecl1() { + var sc = getSC(); + var x = void 0; + + switch (tokens[pos].bd_kind) { + case 1: + x = getDeclaration(); + break; + case 2: + x = getAtrule(); + break; + } + + return sc.concat([x]).concat(getSC()).concat([getDeclDelim()]).concat(getSC()); + } + + /** * @param {Number} i Token's index number - * @returns {Number} - */function checkBlockdecl2(i){var start=i;var l=undefined;if(l = checkSC(i))i += l;if(l = checkConditionalStatement(i))tokens[i].bd_kind = 1;else if(l = checkInclude(i))tokens[i].bd_kind = 2;else if(l = checkExtend(i))tokens[i].bd_kind = 4;else if(l = checkMixin(i))tokens[i].bd_kind = 8;else if(l = checkLoop(i))tokens[i].bd_kind = 3;else if(l = checkAtrule(i))tokens[i].bd_kind = 6;else if(l = checkRuleset(i))tokens[i].bd_kind = 7;else if(l = checkDeclaration(i))tokens[i].bd_kind = 5;else return 0;i += l;if(l = checkSC(i))i += l;return i - start;} /** - * @returns {Array} - */function getBlockdecl2(){var sc=getSC();var x=undefined;switch(tokens[pos].bd_kind){case 1:x = getConditionalStatement();break;case 2:x = getInclude();break;case 3:x = getLoop();break;case 4:x = getExtend();break;case 5:x = getDeclaration();break;case 6:x = getAtrule();break;case 7:x = getRuleset();break;case 8:x = getMixin();break;}return sc.concat([x]).concat(getSC());} /** + * @return {Number} + */ + function checkBlockdecl2(i) { + var start = i; + var l = void 0; + + if (l = checkSC(i)) i += l; + + if (l = checkDeclaration(i)) tokens[i].bd_kind = 1;else if (l = checkAtrule(i)) tokens[i].bd_kind = 2;else return 0; + + i += l; + + if (l = checkSC(i)) i += l; + + return i - start; + } + + /** + * @return {Array} + */ + function getBlockdecl2() { + var sc = getSC(); + var x = void 0; + + switch (tokens[pos].bd_kind) { + case 1: + x = getDeclaration(); + break; + case 2: + x = getAtrule(); + break; + } + + return sc.concat([x]).concat(getSC()); + } + + /** * @param {Number} i Token's index number - * @returns {Number} - */function checkBlockdecl3(i){var start=i;var l=undefined;if(l = checkSC(i))i += l;if(l = checkDeclDelim(i))i += l;else return 0;if(l = checkSC(i))i += l;return i - start;} /** - * @returns {Array} `[s0, ['declDelim'], s1]` where `s0` and `s1` are - * are optional whitespaces. - */function getBlockdecl3(){return getSC().concat([getDeclDelim()]).concat(getSC());} /** + * @return {Number} + */ + function checkBlockdecl3(i) { + var start = i; + var l = void 0; + + if (l = checkSC(i)) i += l; + + if (l = checkDeclDelim(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + return i - start; + } + + /** + * @return {Array} + */ + function getBlockdecl3() { + return getSC().concat([getDeclDelim()]).concat(getSC()); + } + + /** * @param {Number} i Token's index number - * @returns {Number} - */function checkBlockdecl4(i){return checkSC(i);} /** - * @returns {Array} - */function getBlockdecl4(){return getSC();} /** + * @return {Number} + */ + function checkBlockdecl4(i) { + return checkSC(i); + } + + /** + * @return {Array} + */ + function getBlockdecl4() { + return getSC(); + } + + /** * Check if token is part of text inside square brackets, e.g. `[1]` * @param {Number} i Token's index number - * @returns {Number} - */function checkBrackets(i){if(i >= tokensLength || tokens[i].type !== TokenType.LeftSquareBracket)return 0;return tokens[i].right - i + 1;} /** - * Get node with text inside parentheses or square brackets (e.g. `(1)`) + * @return {Number} + */ + function checkBrackets(i) { + if (i >= tokensLength) return 0; + + var start = i; + + if (tokens[i].type === TokenType.LeftSquareBracket) i++;else return 0; + + if (i < tokens[start].right) { + var l = checkTsets(i); + if (l) i += l;else return 0; + } + + i++; + + return i - start; + } + + /** + * Get node with text inside square brackets, e.g. `[1]` * @return {Node} - */function getBrackets(){var startPos=pos;var token=tokens[startPos];var line=token.ln;var column=token.col;pos++;var tsets=getTsets();var end=getLastPosition(tsets,line,column,1);pos++;return newNode(NodeType.BracketsType,tsets,token.ln,token.col,end);} /** + */ + function getBrackets() { + var type = NodeType.BracketsType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + + var tsets = []; + var right = token.right; + + pos++; + + if (pos < right) { + tsets = getTsets(); + } + + var end = getLastPosition(tsets, line, column, 1); + pos++; + + return newNode(type, tsets, line, column, end); + } + + /** * Check if token is part of a class selector (e.g. `.abc`) * @param {Number} i Token's index number - * @returns {Number} Length of the class selector - */function checkClass(i){var start=i;var l=undefined;if(i >= tokensLength)return 0;if(tokens[i].class_l)return tokens[i].class_l;if(tokens[i++].type !== TokenType.FullStop)return 0;if(l = checkIdentOrInterpolation(i))i += l;else return 0;return i - start;} /** + * @return {Number} Length of the class selector + */ + function checkClass(i) { + var l; + + if (i >= tokensLength) return 0; + + if (tokens[i].class_l) return tokens[i].class_l; + + if (tokens[i++].type === TokenType.FullStop && (l = checkIdent(i))) { + tokens[i].class_l = l + 1; + return l + 1; + } + + return 0; + } + + /** * Get node with a class selector - * @returns {Array} `['class', ['ident', x]]` where x is a class's - * identifier (without `.`, e.g. `abc`). - */function getClass(){var startPos=pos;var x=[];pos++;x = x.concat(getIdentOrInterpolation());var token=tokens[startPos];return newNode(NodeType.ClassType,x,token.ln,token.col);}function checkCombinator(i){if(i >= tokensLength)return 0;var l=undefined;if(l = checkCombinator1(i))tokens[i].combinatorType = 1;else if(l = checkCombinator2(i))tokens[i].combinatorType = 2;else if(l = checkCombinator3(i))tokens[i].combinatorType = 3;return l;}function getCombinator(){var type=tokens[pos].combinatorType;if(type === 1)return getCombinator1();if(type === 2)return getCombinator2();if(type === 3)return getCombinator3();} /** + * @return {Node} + */ + function getClass() { + var type = NodeType.ClassType; + var token = tokens[pos++]; + var line = token.ln; + var column = token.col; + var content = [getIdent()]; + + return newNode(type, content, line, column); + } + + function checkCombinator(i) { + if (i >= tokensLength) return 0; + + var l = void 0; + if (l = checkCombinator1(i)) tokens[i].combinatorType = 1;else if (l = checkCombinator2(i)) tokens[i].combinatorType = 2;else if (l = checkCombinator3(i)) tokens[i].combinatorType = 3; + + return l; + } + + function getCombinator() { + var type = tokens[pos].combinatorType; + if (type === 1) return getCombinator1(); + if (type === 2) return getCombinator2(); + if (type === 3) return getCombinator3(); + } + /** * (1) `||` - */function checkCombinator1(i){if(tokens[i].type === TokenType.VerticalLine && tokens[i + 1].type === TokenType.VerticalLine)return 2;else return 0;}function getCombinator1(){var type=NodeType.CombinatorType;var token=tokens[pos];var line=token.ln;var column=token.col;var content='||';pos += 2;return newNode(type,content,line,column);} /** + */ + function checkCombinator1(i) { + if (tokens[i].type === TokenType.VerticalLine && tokens[i + 1].type === TokenType.VerticalLine) return 2;else return 0; + } + + function getCombinator1() { + var type = NodeType.CombinatorType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = '||'; + + pos += 2; + return newNode(type, content, line, column); + } + + /** * (1) `>` * (2) `+` * (3) `~` - */function checkCombinator2(i){var type=tokens[i].type;if(type === TokenType.PlusSign || type === TokenType.GreaterThanSign || type === TokenType.Tilde)return 1;else return 0;}function getCombinator2(){var type=NodeType.CombinatorType;var token=tokens[pos];var line=token.ln;var column=token.col;var content=tokens[pos++].value;return newNode(type,content,line,column);} /** + */ + function checkCombinator2(i) { + var type = tokens[i].type; + if (type === TokenType.PlusSign || type === TokenType.GreaterThanSign || type === TokenType.Tilde) return 1;else return 0; + } + + function getCombinator2() { + var type = NodeType.CombinatorType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = tokens[pos++].value; + + return newNode(type, content, line, column); + } + + /** * (1) `/panda/` - */function checkCombinator3(i){var start=i;if(tokens[i].type === TokenType.Solidus)i++;else return 0;var l=undefined;if(l = checkIdent(i))i += l;else return 0;if(tokens[i].type === TokenType.Solidus)i++;else return 0;return i - start;}function getCombinator3(){var type=NodeType.CombinatorType;var token=tokens[pos];var line=token.ln;var column=token.col; // Skip `/`. - pos++;var ident=getIdent(); // Skip `/`. - pos++;var content='/' + ident.content + '/';return newNode(type,content,line,column);} /** + */ + function checkCombinator3(i) { + var start = i; + + if (tokens[i].type === TokenType.Solidus) i++;else return 0; + + var l = void 0; + if (l = checkIdent(i)) i += l;else return 0; + + if (tokens[i].type === TokenType.Solidus) i++;else return 0; + + return i - start; + } + + function getCombinator3() { + var type = NodeType.CombinatorType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + + // Skip `/`. + pos++; + var ident = getIdent(); + + // Skip `/`. + pos++; + + var content = '/' + ident.content + '/'; + + return newNode(type, content, line, column); + } + + /** * Check if token is a multiline comment. * @param {Number} i Token's index number - * @returns {Number} `1` if token is a multiline comment, otherwise `0` - */function checkCommentML(i){return i < tokensLength && tokens[i].type === TokenType.CommentML?1:0;} /** + * @return {Number} `1` if token is a multiline comment, otherwise `0` + */ + function checkCommentML(i) { + return i < tokensLength && tokens[i].type === TokenType.CommentML ? 1 : 0; + } + + /** * Get node with a multiline comment - * @returns {Array} `['commentML', x]` where `x` - * is the comment's text (without `/*` and `* /`). - */function getCommentML(){var startPos=pos;var s=tokens[pos].value.substring(2);var l=s.length;var token=tokens[startPos];var line=token.ln;var column=token.col;if(s.charAt(l - 2) === '*' && s.charAt(l - 1) === '/')s = s.substring(0,l - 2);var end=getLastPosition(s,line,column,2);if(end[0] === line)end[1] += 2;pos++;return newNode(NodeType.CommentMLType,s,token.ln,token.col,end);} /** - * Check if token is part of a single-line comment. - * @param {Number} i Token's index number - * @returns {Number} `1` if token is a single-line comment, otherwise `0` - */function checkCommentSL(i){return i < tokensLength && tokens[i].type === TokenType.CommentSL?1:0;} /** - * Get node with a single-line comment. - * @returns {Array} `['commentSL', x]` where `x` is comment's message - * (without `//`) - */function getCommentSL(){var startPos=pos;var x=undefined;var token=tokens[startPos];var line=token.ln;var column=token.col;x = tokens[pos++].value.substring(2);var end=getLastPosition(x,line,column + 2);return newNode(NodeType.CommentSLType,x,token.ln,token.col,end);} /** - * Check if token is part of a condition - * (e.g. `@if ...`, `@else if ...` or `@else ...`). - * @param {Number} i Token's index number - * @returns {Number} Length of the condition - */function checkCondition(i){var start=i;var l=undefined;var _i=undefined;var s=undefined;if(i >= tokensLength)return 0;if(l = checkAtkeyword(i))i += l;else return 0;if(['if','else'].indexOf(tokens[start + 1].value) < 0)return 0;while(i < tokensLength) {if(l = checkBlock(i))break;s = checkSC(i);_i = i + s;if(l = _checkCondition(_i))i += l + s;else break;}return i - start;}function _checkCondition(i){return checkVariable(i) || checkNumber(i) || checkInterpolation(i) || checkIdent(i) || checkOperator(i) || checkCombinator(i) || checkString(i);} /** - * Get node with a condition. - * @returns {Array} `['condition', x]` - */function getCondition(){var startPos=pos;var x=[];var s;var _pos;x.push(getAtkeyword());while(pos < tokensLength) {if(checkBlock(pos))break;s = checkSC(pos);_pos = pos + s;if(!_checkCondition(_pos))break;if(s)x = x.concat(getSC());x.push(_getCondition());}var token=tokens[startPos];return newNode(NodeType.ConditionType,x,token.ln,token.col);}function _getCondition(){if(checkVariable(pos))return getVariable();if(checkNumber(pos))return getNumber();if(checkInterpolation(pos))return getInterpolation();if(checkIdent(pos))return getIdent();if(checkOperator(pos))return getOperator();if(checkCombinator(pos))return getCombinator();if(checkString(pos))return getString();} /** - * Check if token is part of a conditional statement - * (e.g. `@if ... {} @else if ... {} @else ... {}`). - * @param {Number} i Token's index number - * @returns {Number} Length of the condition - */function checkConditionalStatement(i){var start=i;var l=undefined;if(i >= tokensLength)return 0;if(l = checkCondition(i))i += l;else return 0;if(l = checkSC(i))i += l;if(l = checkBlock(i))i += l;else return 0;return i - start;} /** - * Get node with a condition. - * @returns {Array} `['condition', x]` - */function getConditionalStatement(){var startPos=pos;var x=[];x.push(getCondition());x = x.concat(getSC());x.push(getBlock());var token=tokens[startPos];return newNode(NodeType.ConditionalStatementType,x,token.ln,token.col);} /** + * @return {Node} + */ + function getCommentML() { + var type = NodeType.CommentMLType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = tokens[pos].value.substring(2); + var l = content.length; + + if (content.charAt(l - 2) === '*' && content.charAt(l - 1) === '/') content = content.substring(0, l - 2); + + var end = getLastPosition(content, line, column, 2); + if (end[0] === line) end[1] += 2; + pos++; + + return newNode(type, content, line, column, end); + } + + /** * Check if token is part of a declaration (property-value pair) * @param {Number} i Token's index number - * @returns {Number} Length of the declaration - */function checkDeclaration(i){var start=i;var l=undefined;if(i >= tokensLength)return 0;if(l = checkProperty(i))i += l;else return 0;if(l = checkSC(i))i += l;if(l = checkPropertyDelim(i))i++;else return 0;if(l = checkSC(i))i += l;if(l = checkValue(i))i += l;else return 0;return i - start;} /** + * @return {Number} Length of the declaration + */ + function checkDeclaration(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkProperty(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkPropertyDelim(i)) i++;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkValue(i)) i += l;else return 0; + + return i - start; + } + + /** * Get node with a declaration - * @returns {Array} `['declaration', ['property', x], ['propertyDelim'], - * ['value', y]]` - */function getDeclaration(){var startPos=pos;var x=[];x.push(getProperty());x = x.concat(getSC());x.push(getPropertyDelim());x = x.concat(getSC());x.push(getValue());var token=tokens[startPos];return newNode(NodeType.DeclarationType,x,token.ln,token.col);} /** + * @return {Node} + */ + function getDeclaration() { + var type = NodeType.DeclarationType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + + var content = [getProperty()].concat(getSC()).concat([getPropertyDelim()]).concat(getSC()).concat([getValue()]); + + return newNode(type, content, line, column); + } + + /** * Check if token is a semicolon * @param {Number} i Token's index number - * @returns {Number} `1` if token is a semicolon, otherwise `0` - */function checkDeclDelim(i){return i < tokensLength && tokens[i].type === TokenType.Semicolon?1:0;} /** + * @return {Number} `1` if token is a semicolon, otherwise `0` + */ + function checkDeclDelim(i) { + return i < tokensLength && tokens[i].type === TokenType.Semicolon ? 1 : 0; + } + + /** * Get node with a semicolon - * @returns {Array} `['declDelim']` - */function getDeclDelim(){var startPos=pos++;var token=tokens[startPos];return newNode(NodeType.DeclDelimType,';',token.ln,token.col);} /** - * Check if token if part of `!default` word. - * @param {Number} i Token's index number - * @returns {Number} Length of the `!default` word - */function checkDefault(i){var start=i;var l=undefined;if(i >= tokensLength || tokens[i++].type !== TokenType.ExclamationMark)return 0;if(l = checkSC(i))i += l;if(tokens[i].value === 'default'){tokens[start].defaultEnd = i;return i - start + 1;}else {return 0;}} /** - * Get node with a `!default` word - * @returns {Array} `['default', sc]` where `sc` is optional whitespace - */function getDefault(){var token=tokens[pos];var line=token.ln;var column=token.col;var content=joinValues(pos,token.defaultEnd);pos = token.defaultEnd + 1;return newNode(NodeType.DefaultType,content,line,column);} /** + * @return {Node} + */ + function getDeclDelim() { + var type = NodeType.DeclDelimType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = ';'; + + pos++; + + return newNode(type, content, line, column); + } + + /** * Check if token is a comma * @param {Number} i Token's index number - * @returns {Number} `1` if token is a comma, otherwise `0` - */function checkDelim(i){return i < tokensLength && tokens[i].type === TokenType.Comma?1:0;} /** + * @return {Number} `1` if token is a comma, otherwise `0` + */ + function checkDelim(i) { + return i < tokensLength && tokens[i].type === TokenType.Comma ? 1 : 0; + } + + /** * Get node with a comma - * @returns {Array} `['delim']` - */function getDelim(){var startPos=pos;pos++;var token=tokens[startPos];return newNode(NodeType.DelimType,',',token.ln,token.col);} /** + * @return {Node} + */ + function getDelim() { + var type = NodeType.DelimType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = ','; + + pos++; + + return newNode(type, content, line, column); + } + + /** * Check if token is part of a number with dimension unit (e.g. `10px`) * @param {Number} i Token's index number - * @returns {Number} - */function checkDimension(i){var ln=checkNumber(i);var li=undefined;if(i >= tokensLength || !ln || i + ln >= tokensLength)return 0;return (li = checkNmName2(i + ln))?ln + li:0;} /** + * @return {Number} + */ + function checkDimension(i) { + var ln = checkNumber(i); + var li = void 0; + + if (i >= tokensLength || !ln || i + ln >= tokensLength) return 0; + + return (li = checkUnit(i + ln)) ? ln + li : 0; + } + + /** * Get node of a number with dimension unit - * @returns {Array} `['dimension', ['number', x], ['ident', y]]` where - * `x` is a number converted to string (e.g. `'10'`) and `y` is - * a dimension unit (e.g. `'px'`). - */function getDimension(){var startPos=pos;var x=[getNumber()];var token=tokens[pos];var ident=newNode(NodeType.IdentType,getNmName2(),token.ln,token.col);x.push(ident);token = tokens[startPos];return newNode(NodeType.DimensionType,x,token.ln,token.col);} /** + * @return {Node} + */ + function getDimension() { + var type = NodeType.DimensionType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = [getNumber(), getUnit()]; + + return newNode(type, content, line, column); + } + + /** + * Check if token is unit * @param {Number} i Token's index number - * @returns {Number} - */function checkExpression(i){var start=i;if(i >= tokensLength || tokens[i++].value !== 'expression' || i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis)return 0;return tokens[i].right - start + 1;} /** - * @returns {Array} - */function getExpression(){var startPos=pos;var e;var token=tokens[startPos];var line=token.ln;var column=token.col;pos++;e = joinValues(pos + 1,tokens[pos].right - 1);var end=getLastPosition(e,line,column,1);if(end[0] === line)end[1] += 11;pos = tokens[pos].right + 1;return newNode(NodeType.ExpressionType,e,token.ln,token.col,end);}function checkExtend(i){var l=0;if(l = checkExtend1(i))tokens[i].extend_child = 1;else if(l = checkExtend2(i))tokens[i].extend_child = 2;return l;}function getExtend(){var type=tokens[pos].extend_child;if(type === 1)return getExtend1();else if(type === 2)return getExtend2();} /** - * Checks if token is part of an extend with `!optional` flag. - * @param {Number} i - */function checkExtend1(i){var start=i;var l;if(i >= tokensLength)return 0;if(l = checkAtkeyword(i))i += l;else return 0;if(tokens[start + 1].value !== 'extend')return 0;if(l = checkSC(i))i += l;else return 0;if(l = checkSelectorsGroup(i))i += l;else return 0;if(l = checkSC(i))i += l;else return 0;if(l = checkOptional(i))i += l;else return 0;return i - start;}function getExtend1(){var startPos=pos;var x=[].concat([getAtkeyword()],getSC(),getSelectorsGroup(),getSC(),[getOptional()]);var token=tokens[startPos];return newNode(NodeType.ExtendType,x,token.ln,token.col);} /** - * Checks if token is part of an extend without `!optional` flag. - * @param {Number} i - */function checkExtend2(i){var start=i;var l;if(i >= tokensLength)return 0;if(l = checkAtkeyword(i))i += l;else return 0;if(tokens[start + 1].value !== 'extend')return 0;if(l = checkSC(i))i += l;else return 0;if(l = checkSelectorsGroup(i))i += l;else return 0;return i - start;}function getExtend2(){var startPos=pos;var x=[].concat([getAtkeyword()],getSC(),getSelectorsGroup());var token=tokens[startPos];return newNode(NodeType.ExtendType,x,token.ln,token.col);} /** + * @return {Number} + */ + function checkUnit(i) { + var units = ['em', 'ex', 'ch', 'rem', 'vh', 'vw', 'vmin', 'vmax', 'px', 'mm', 'q', 'cm', 'in', 'pt', 'pc', 'deg', 'grad', 'rad', 'turn', 's', 'ms', 'Hz', 'kHz', 'dpi', 'dpcm', 'dppx']; + + return units.indexOf(tokens[i].value) !== -1 ? 1 : 0; + } + + /** + * Get unit node of type ident + * @return {Node} An ident node containing the unit value + */ + function getUnit() { + var type = NodeType.IdentType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = token.value; + + pos++; + + return newNode(type, content, line, column); + } + + /** * @param {Number} i Token's index number - * @returns {Number} - */function checkFunction(i){var start=i;var l=undefined;if(i >= tokensLength)return 0;if(l = checkIdentOrInterpolation(i))i += l;else return 0;return i < tokensLength && tokens[i].type === TokenType.LeftParenthesis?tokens[i].right - start + 1:0;} /** - * @returns {Array} - */function getFunction(){var startPos=pos;var x=getIdentOrInterpolation();var body=undefined;body = getArguments();x.push(body);var token=tokens[startPos];return newNode(NodeType.FunctionType,x,token.ln,token.col);} /** - * @returns {Array} - */function getArguments(){var startPos=pos;var x=[];var body=undefined;var token=tokens[startPos];var line=token.ln;var column=token.col;pos++;while(pos < tokensLength && tokens[pos].type !== TokenType.RightParenthesis) {if(checkDeclaration(pos))x.push(getDeclaration());else if(checkArgument(pos)){body = getArgument();if(typeof body.content === 'string')x.push(body);else x = x.concat(body);}else if(checkClass(pos))x.push(getClass());else throwError();}var end=getLastPosition(x,line,column,1);pos++;return newNode(NodeType.ArgumentsType,x,token.ln,token.col,end);} /** - * Check if token is part of an identifier + * @return {Number} + */ + function checkExpression(i) { + var start = i; + + if (i >= tokensLength || tokens[i++].value !== 'expression' || i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis) { + return 0; + } + + return tokens[i].right - start + 1; + } + + /** + * @return {Node} + */ + function getExpression() { + var type = NodeType.ExpressionType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + + pos++; + + var content = joinValues(pos + 1, tokens[pos].right - 1); + var end = getLastPosition(content, line, column, 1); + if (end[0] === line) end[1] += 11; + pos = tokens[pos].right + 1; + + return newNode(type, content, line, column, end); + } + + /** * @param {Number} i Token's index number - * @returns {Number} Length of the identifier - */function checkIdent(i){var start=i;var interpolations=[];var wasIdent=undefined;var wasInt=false;var l=undefined;if(i >= tokensLength)return 0; // Check if token is part of an identifier starting with `_`: - if(tokens[i].type === TokenType.LowLine)return checkIdentLowLine(i);if(tokens[i].type === TokenType.HyphenMinus && tokens[i + 1].type === TokenType.DecimalNumber)return 0; // If token is a character, `-`, `$` or `*`, skip it & continue: - if(l = _checkIdent(i))i += l;else return 0; // Remember if previous token's type was identifier: - wasIdent = tokens[i - 1].type === TokenType.Identifier;while(i < tokensLength) {l = _checkIdent(i);if(!l)break;wasIdent = true;i += l;}if(!wasIdent && !wasInt && tokens[start].type !== TokenType.Asterisk)return 0;tokens[start].ident_last = i - 1;if(interpolations.length)tokens[start].interpolations = interpolations;return i - start;}function _checkIdent(i){if(tokens[i].type === TokenType.HyphenMinus || tokens[i].type === TokenType.Identifier || tokens[i].type === TokenType.DollarSign || tokens[i].type === TokenType.LowLine || tokens[i].type === TokenType.DecimalNumber || tokens[i].type === TokenType.Asterisk)return 1;return 0;} /** - * Check if token is part of an identifier starting with `_` + * @return {Number} + */ + function checkFunction(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkIdent(i)) i += l;else return 0; + + return i < tokensLength && tokens[i].type === TokenType.LeftParenthesis ? tokens[i].right - start + 1 : 0; + } + + /** + * @return {Node} + */ + function getFunction() { + var type = NodeType.FunctionType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var ident = getIdent(); + var content = [ident]; + + content.push(getArguments()); + + return newNode(type, content, line, column); + } + + /** + * @return {Node} + */ + function getArguments() { + var type = NodeType.ArgumentsType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + var body = void 0; + + pos++; + + while (pos < tokensLength && tokens[pos].type !== TokenType.RightParenthesis) { + if (checkDeclaration(pos)) content.push(getDeclaration());else if (checkArgument(pos)) { + body = getArgument(); + if (typeof body.content === 'string') content.push(body);else content = content.concat(body); + } else if (checkClass(pos)) content.push(getClass());else throwError(pos); + } + + var end = getLastPosition(content, line, column, 1); + pos++; + + return newNode(type, content, line, column, end); + } + + /** * @param {Number} i Token's index number - * @returns {Number} Length of the identifier - */function checkIdentLowLine(i){var start=i;if(i++ >= tokensLength)return 0;for(;i < tokensLength;i++) {if(tokens[i].type !== TokenType.HyphenMinus && tokens[i].type !== TokenType.DecimalNumber && tokens[i].type !== TokenType.LowLine && tokens[i].type !== TokenType.Identifier)break;} // Save index number of the last token of the identifier: - tokens[start].ident_last = i - 1;return i - start;} /** + * @return {Number} + */ + function checkArgument(i) { + var l; + + if (l = checkVhash(i)) tokens[i].argument_child = 1;else if (l = checkAny(i)) tokens[i].argument_child = 2;else if (l = checkSC(i)) tokens[i].argument_child = 3;else if (l = checkOperator(i)) tokens[i].argument_child = 4; + + return l; + } + + /** + * @return {Node} + */ + function getArgument() { + var childType = tokens[pos].argument_child; + if (childType === 1) return getVhash();else if (childType === 2) return getAny();else if (childType === 3) return getSC();else if (childType === 4) return getOperator(); + } + + /** + * Check if token is part of an identifierю + * Grammar from CSS spec: + * h [0-9a-f] + * nonascii [\240-\377] + * unicode \\{h}{1,6}(\r\n|[ \t\r\n\f])? + * escape {unicode}|\\[^\r\n\f0-9a-f] + * nmstart [_a-z]|{nonascii}|{escape} + * nmchar [_a-z0-9-]|{nonascii}|{escape} + * ident -?{nmstart}{nmchar}* + * + * @param {number} i Token's index number + * @return {number} Length of the identifier + */ + function checkIdent(i) { + var start = i; + + if (i >= tokensLength) return 0; + + if (tokens[i].type === TokenType.HyphenMinus) i++; + + if (tokens[i].type === TokenType.LowLine || tokens[i].type === TokenType.Identifier) i++;else return 0; + + for (; i < tokensLength; i++) { + if (tokens[i].type !== TokenType.HyphenMinus && tokens[i].type !== TokenType.LowLine && tokens[i].type !== TokenType.Identifier && tokens[i].type !== TokenType.DecimalNumber) break; + } + + tokens[start].ident_last = i - 1; + + return i - start; + } + + /** * Get node with an identifier - * @returns {Array} `['ident', x]` where `x` is identifier's name - */function getIdent(){var startPos=pos;var x=joinValues(pos,tokens[pos].ident_last);pos = tokens[pos].ident_last + 1;var token=tokens[startPos];return newNode(NodeType.IdentType,x,token.ln,token.col);}function checkIdentOrInterpolation(i){var start=i;var l=undefined;while(i < tokensLength) {if(l = checkInterpolation(i) || checkIdent(i))i += l;else break;}return i - start;}function getIdentOrInterpolation(){var x=[];while(pos < tokensLength) {if(checkInterpolation(pos))x.push(getInterpolation());else if(checkIdent(pos))x.push(getIdent());else break;}return x;} /** + * @return {Node} + */ + function getIdent() { + var type = NodeType.IdentType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = joinValues(pos, tokens[pos].ident_last); + + pos = tokens[pos].ident_last + 1; + + return newNode(type, content, line, column); + } + + /** * Check if token is part of `!important` word * @param {Number} i Token's index number - * @returns {Number} - */function checkImportant(i){var start=i;var l=undefined;if(i >= tokensLength || tokens[i++].type !== TokenType.ExclamationMark)return 0;if(l = checkSC(i))i += l;if(tokens[i].value === 'important'){tokens[start].importantEnd = i;return i - start + 1;}else {return 0;}} /** + * @return {Number} + */ + function checkImportant(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength || tokens[i++].type !== TokenType.ExclamationMark) return 0; + + if (l = checkSC(i)) i += l; + + if (tokens[i].value === 'important') { + tokens[start].importantEnd = i; + return i - start + 1; + } else { + return 0; + } + } + + /** * Get node with `!important` word - * @returns {Array} `['important', sc]` where `sc` is optional whitespace - */function getImportant(){var token=tokens[pos];var line=token.ln;var column=token.col;var content=joinValues(pos,token.importantEnd);pos = token.importantEnd + 1;return newNode(NodeType.ImportantType,content,line,column);} /** - * Check if token is part of an included mixin (`@include` or `@extend` - * directive). - * @param {Number} i Token's index number - * @returns {Number} Length of the included mixin - */function checkInclude(i){var l;if(i >= tokensLength)return 0;if(l = checkInclude1(i))tokens[i].include_type = 1;else if(l = checkInclude2(i))tokens[i].include_type = 2;else if(l = checkInclude3(i))tokens[i].include_type = 3;else if(l = checkInclude4(i))tokens[i].include_type = 4;else if(l = checkInclude5(i))tokens[i].include_type = 5;return l;} /** - * Check if token is part of `!global` word - * @param {Number} i Token's index number + * @return {Node} + */ + function getImportant() { + var type = NodeType.ImportantType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = joinValues(pos, token.importantEnd); + + pos = token.importantEnd + 1; + + return newNode(type, content, line, column); + } + + /** + * Check a single keyframe block - `5% {}` + * @param {Number} i * @returns {Number} - */function checkGlobal(i){var start=i;var l=undefined;if(i >= tokensLength || tokens[i++].type !== TokenType.ExclamationMark)return 0;if(l = checkSC(i))i += l;if(tokens[i].value === 'global'){tokens[start].globalEnd = i;return i - start + 1;}else {return 0;}} /** - * Get node with `!global` word - */function getGlobal(){var token=tokens[pos];var line=token.ln;var column=token.col;var content=joinValues(pos,token.globalEnd);pos = token.globalEnd + 1;return newNode(NodeType.GlobalType,content,line,column);} /** - * Get node with included mixin - * @returns {Array} `['include', x]` - */function getInclude(){switch(tokens[pos].include_type){case 1:return getInclude1();case 2:return getInclude2();case 3:return getInclude3();case 4:return getInclude4();case 5:return getInclude5();}} /** - * Get node with included mixin with keyfames selector like - * `@include nani(foo) { 0% {}}` - * @param {Number} i Token's index number - * @returns {Number} Length of the include - */function checkInclude1(i){var start=i;var l=undefined;if(l = checkAtkeyword(i))i += l;else return 0;if(tokens[start + 1].value !== 'include')return 0;if(l = checkSC(i))i += l;else return 0;if(l = checkIdentOrInterpolation(i))i += l;else return 0;if(l = checkSC(i))i += l;if(l = checkArguments(i))i += l;else return 0;if(l = checkSC(i))i += l;if(l = checkKeyframesBlocks(i))i += l;else return 0;return i - start;} /** - * Get node with included mixin with keyfames selector like - * `@include nani(foo) { 0% {}}` - * @returns {Array} `['include', ['atkeyword', x], sc, ['selector', y], sc, - * ['arguments', z], sc, ['block', q], sc` where `x` is `include` or - * `extend`, `y` is mixin's identifier (selector), `z` are arguments - * passed to the mixin, `q` is block passed to the mixin containing a - * ruleset > selector > keyframesSelector, and `sc` are optional - * whitespaces - */function getInclude1(){var startPos=pos;var x=[].concat(getAtkeyword(),getSC(),getIdentOrInterpolation(),getSC(),getArguments(),getSC(),getKeyframesBlocks());var token=tokens[startPos];return newNode(NodeType.IncludeType,x,token.ln,token.col);} /** - * Check if token is part of an included mixin like `@include nani(foo) {...}` - * @param {Number} i Token's index number - * @returns {Number} Length of the include - */function checkInclude2(i){var start=i;var l=undefined;if(l = checkAtkeyword(i))i += l;else return 0;if(tokens[start + 1].value !== 'include')return 0;if(l = checkSC(i))i += l;else return 0;if(l = checkIdentOrInterpolation(i))i += l;else return 0;if(l = checkSC(i))i += l;if(l = checkArguments(i))i += l;else return 0;if(l = checkSC(i))i += l;if(l = checkBlock(i))i += l;else return 0;return i - start;} /** - * Get node with included mixin like `@include nani(foo) {...}` - * @returns {Array} `['include', ['atkeyword', x], sc, ['selector', y], sc, - * ['arguments', z], sc, ['block', q], sc` where `x` is `include` or - * `extend`, `y` is mixin's identifier (selector), `z` are arguments - * passed to the mixin, `q` is block passed to the mixin and `sc` - * are optional whitespaces - */function getInclude2(){var startPos=pos;var x=[].concat(getAtkeyword(),getSC(),getIdentOrInterpolation(),getSC(),getArguments(),getSC(),getBlock());var token=tokens[startPos];return newNode(NodeType.IncludeType,x,token.ln,token.col);} /** - * Check if token is part of an included mixin like `@include nani(foo)` - * @param {Number} i Token's index number - * @returns {Number} Length of the include - */function checkInclude3(i){var start=i;var l=undefined;if(l = checkAtkeyword(i))i += l;else return 0;if(tokens[start + 1].value !== 'include')return 0;if(l = checkSC(i))i += l;else return 0;if(l = checkIdentOrInterpolation(i))i += l;else return 0;if(l = checkSC(i))i += l;if(l = checkArguments(i))i += l;else return 0;return i - start;} /** - * Get node with included mixin like `@include nani(foo)` - * @returns {Array} `['include', ['atkeyword', x], sc, ['selector', y], sc, - * ['arguments', z], sc]` where `x` is `include` or `extend`, `y` is - * mixin's identifier (selector), `z` are arguments passed to the - * mixin and `sc` are optional whitespaces - */function getInclude3(){var startPos=pos;var x=[].concat(getAtkeyword(),getSC(),getIdentOrInterpolation(),getSC(),getArguments());var token=tokens[startPos];return newNode(NodeType.IncludeType,x,token.ln,token.col);} /** - * Check if token is part of an included mixin with a content block passed - * as an argument (e.g. `@include nani {...}`) - * @param {Number} i Token's index number - * @returns {Number} Length of the mixin - */function checkInclude4(i){var start=i;var l=undefined;if(l = checkAtkeyword(i))i += l;else return 0;if(tokens[start + 1].value !== 'include')return 0;if(l = checkSC(i))i += l;else return 0;if(l = checkIdentOrInterpolation(i))i += l;else return 0;if(l = checkSC(i))i += l;if(l = checkBlock(i))i += l;else return 0;return i - start;} /** - * Get node with an included mixin with a content block passed - * as an argument (e.g. `@include nani {...}`) - * @returns {Array} `['include', x]` - */function getInclude4(){var startPos=pos;var x=[].concat(getAtkeyword(),getSC(),getIdentOrInterpolation(),getSC(),getBlock());var token=tokens[startPos];return newNode(NodeType.IncludeType,x,token.ln,token.col);} /** - * @param {Number} i Token's index number + */ + function checkKeyframesBlock(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkKeyframesSelectorsGroup(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkBlock(i)) i += l;else return 0; + + return i - start; + } + + /** + * Get a single keyframe block - `5% {}` + * @returns {Node} + */ + function getKeyframesBlock() { + var type = NodeType.RulesetType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = [].concat(getKeyframesSelectorsGroup(), getSC(), [getBlock()]); + + return newNode(type, content, line, column); + } + + /** + * Check all keyframe blocks - `5% {} 100% {}` + * @param {Number} i * @returns {Number} - */function checkInclude5(i){var start=i;var l=undefined;if(l = checkAtkeyword(i))i += l;else return 0;if(tokens[start + 1].value !== 'include')return 0;if(l = checkSC(i))i += l;else return 0;if(l = checkIdentOrInterpolation(i))i += l;else return 0;return i - start;} /** - * @returns {Array} `['include', x]` - */function getInclude5(){var startPos=pos;var x=[].concat(getAtkeyword(),getSC(),getIdentOrInterpolation());var token=tokens[startPos];return newNode(NodeType.IncludeType,x,token.ln,token.col);} /** - * Check if token is part of an interpolated variable (e.g. `#{$nani}`). - * @param {Number} i Token's index number - * @returns {Number} - */function checkInterpolation(i){var start=i;var l=undefined;if(i >= tokensLength)return 0;if(tokens[i].type !== TokenType.NumberSign || !tokens[i + 1] || tokens[i + 1].type !== TokenType.LeftCurlyBracket)return 0;i += 2;while(tokens[i].type !== TokenType.RightCurlyBracket) {if(l = checkArgument(i))i += l;else return 0;}return tokens[i].type === TokenType.RightCurlyBracket?i - start + 1:0;} /** - * Get node with an interpolated variable - * @returns {Array} `['interpolation', x]` - */function getInterpolation(){var startPos=pos;var x=[];var token=tokens[startPos];var line=token.ln;var column=token.col; // Skip `#{`: - pos += 2;while(pos < tokensLength && tokens[pos].type !== TokenType.RightCurlyBracket) {var body=getArgument();if(typeof body.content === 'string')x.push(body);else x = x.concat(body);}var end=getLastPosition(x,line,column,1); // Skip `}`: - pos++;return newNode(NodeType.InterpolationType,x,token.ln,token.col,end);}function checkKeyframesBlock(i){var start=i;var l=undefined;if(i >= tokensLength)return 0;if(l = checkKeyframesSelector(i))i += l;else return 0;if(l = checkSC(i))i += l;if(l = checkBlock(i))i += l;else return 0;return i - start;}function getKeyframesBlock(){var type=NodeType.RulesetType;var token=tokens[pos];var line=token.ln;var column=token.col;var content=[].concat([getKeyframesSelector()],getSC(),[getBlock()]);return newNode(type,content,line,column);}function checkKeyframesBlocks(i){var start=i;var l=undefined;if(i < tokensLength && tokens[i].type === TokenType.LeftCurlyBracket)i++;else return 0;if(l = checkSC(i))i += l;if(l = checkKeyframesBlock(i))i += l;else return 0;while(tokens[i].type !== TokenType.RightCurlyBracket) {if(l = checkSC(i))i += l;else if(l = checkKeyframesBlock(i))i += l;else break;}if(i < tokensLength && tokens[i].type === TokenType.RightCurlyBracket)i++;else return 0;return i - start;}function getKeyframesBlocks(){var type=NodeType.BlockType;var token=tokens[pos];var line=token.ln;var column=token.col;var content=[];var keyframesBlocksEnd=token.right; // Skip `{`. - pos++;while(pos < keyframesBlocksEnd) {if(checkSC(pos))content = content.concat(getSC());else if(checkKeyframesBlock(pos))content.push(getKeyframesBlock());}var end=getLastPosition(content,line,column,1); // Skip `}`. - pos++;return newNode(type,content,line,column,end);} /** + */ + function checkKeyframesBlocks(i) { + var start = i; + var l = void 0; + + if (i < tokensLength && tokens[i].type === TokenType.LeftCurlyBracket) i++;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkKeyframesBlock(i)) i += l;else return 0; + + while (tokens[i].type !== TokenType.RightCurlyBracket) { + if (l = checkSC(i)) i += l;else if (l = checkKeyframesBlock(i)) i += l;else break; + } + + if (i < tokensLength && tokens[i].type === TokenType.RightCurlyBracket) i++;else return 0; + + return i - start; + } + + /** + * Get all keyframe blocks - `5% {} 100% {}` + * @returns {Node} + */ + function getKeyframesBlocks() { + var type = NodeType.BlockType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + var keyframesBlocksEnd = token.right; + + // Skip `{`. + pos++; + + while (pos < keyframesBlocksEnd) { + if (checkSC(pos)) content = content.concat(getSC());else if (checkKeyframesBlock(pos)) content.push(getKeyframesBlock()); + } + + var end = getLastPosition(content, line, column, 1); + + // Skip `}`. + pos++; + + return newNode(type, content, line, column, end); + } + + /** * Check if token is part of a @keyframes rule. * @param {Number} i Token's index number * @return {Number} Length of the @keyframes rule - */function checkKeyframesRule(i){var start=i;var l=undefined;if(i >= tokensLength)return 0;if(l = checkAtkeyword(i))i += l;else return 0;var atruleName=joinValues2(i - l,l);if(atruleName.indexOf('keyframes') === -1)return 0;if(l = checkSC(i))i += l;else return 0;if(l = checkIdentOrInterpolation(i))i += l;else return 0;if(l = checkSC(i))i += l;if(l = checkKeyframesBlocks(i))i += l;else return 0;return i - start;} /** + */ + function checkKeyframesRule(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkAtkeyword(i)) i += l;else return 0; + + var atruleName = joinValues2(i - l, l); + if (atruleName.indexOf('keyframes') === -1) return 0; + + if (l = checkSC(i)) i += l;else return 0; + + if (l = checkIdent(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkKeyframesBlocks(i)) i += l;else return 0; + + return i - start; + } + + /** * @return {Node} - */function getKeyframesRule(){var type=NodeType.AtruleType;var token=tokens[pos];var line=token.ln;var column=token.col;var content=[].concat([getAtkeyword()],getSC(),getIdentOrInterpolation(),getSC(),[getKeyframesBlocks()]);return newNode(type,content,line,column);}function checkKeyframesSelector(i){var start=i;var l=undefined;if(i >= tokensLength)return 0;if(l = checkIdent(i)){ // Valid selectors are only `from` and `to`. - var selector=joinValues2(i,l);if(selector !== 'from' && selector !== 'to')return 0;i += l;tokens[start].keyframesSelectorType = 1;}else if(l = checkPercentage(i)){i += l;tokens[start].keyframesSelectorType = 2;}else if(l = checkInterpolation(i)){i += l;tokens[start].keyframesSelectorType = 3;}else {return 0;}return i - start;}function getKeyframesSelector(){var keyframesSelectorType=NodeType.KeyframesSelectorType;var selectorType=NodeType.SelectorType;var token=tokens[pos];var line=token.ln;var column=token.col;var content=[];if(token.keyframesSelectorType === 1){content.push(getIdent());}else if(token.keyframesSelectorType === 2){content.push(getPercentage());}else {content.push(getInterpolation());}var keyframesSelector=newNode(keyframesSelectorType,content,line,column);return newNode(selectorType,[keyframesSelector],line,column);} /** - * Check if token is part of a loop. - * @param {Number} i Token's index number - * @returns {Number} Length of the loop - */function checkLoop(i){var start=i;var l=undefined;if(i >= tokensLength)return 0;if(l = checkAtkeyword(i))i += l;else return 0;if(['for','each','while'].indexOf(tokens[start + 1].value) < 0)return 0;while(i < tokensLength) {if(l = checkBlock(i)){i += l;break;}else if(l = checkVariable(i) || checkNumber(i) || checkInterpolation(i) || checkIdent(i) || checkSC(i) || checkOperator(i) || checkCombinator(i) || checkString(i))i += l;else return 0;}return i - start;} /** - * Get node with a loop. - * @returns {Array} `['loop', x]` - */function getLoop(){var startPos=pos;var x=[];x.push(getAtkeyword());while(pos < tokensLength) {if(checkBlock(pos)){x.push(getBlock());break;}else if(checkVariable(pos))x.push(getVariable());else if(checkNumber(pos))x.push(getNumber());else if(checkInterpolation(pos))x.push(getInterpolation());else if(checkIdent(pos))x.push(getIdent());else if(checkOperator(pos))x.push(getOperator());else if(checkCombinator(pos))x.push(getCombinator());else if(checkSC(pos))x = x.concat(getSC());else if(checkString(pos))x.push(getString());}var token=tokens[startPos];return newNode(NodeType.LoopType,x,token.ln,token.col);} /** - * Check if token is part of a mixin - * @param {Number} i Token's index number - * @returns {Number} Length of the mixin - */function checkMixin(i){var start=i;var l=undefined;if(i >= tokensLength)return 0;if((l = checkAtkeyword(i)) && tokens[i + 1].value === 'mixin')i += l;else return 0;if(l = checkSC(i))i += l;if(l = checkIdentOrInterpolation(i))i += l;else return 0;if(l = checkSC(i))i += l;if(l = checkArguments(i))i += l;if(l = checkSC(i))i += l;if(l = checkBlock(i))i += l;else return 0;return i - start;} /** - * Get node with a mixin - * @returns {Array} `['mixin', x]` - */function getMixin(){var startPos=pos;var x=[getAtkeyword()];x = x.concat(getSC());if(checkIdentOrInterpolation(pos))x = x.concat(getIdentOrInterpolation());x = x.concat(getSC());if(checkArguments(pos))x.push(getArguments());x = x.concat(getSC());if(checkBlock(pos))x.push(getBlock());var token=tokens[startPos];return newNode(NodeType.MixinType,x,token.ln,token.col);} /** + */ + function getKeyframesRule() { + var type = NodeType.AtruleType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = [].concat([getAtkeyword()], getSC(), [getIdent()], getSC(), [getKeyframesBlocks()]); + + return newNode(type, content, line, column); + } + + /** + * Check a single keyframe selector - `5%`, `from` etc + * @param {Number} i + * @returns {Number} + */ + function checkKeyframesSelector(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkIdent(i)) { + // Valid selectors are only `from` and `to`. + var selector = joinValues2(i, l); + if (selector !== 'from' && selector !== 'to') return 0; + + i += l; + tokens[start].keyframesSelectorType = 1; + } else if (l = checkPercentage(i)) { + i += l; + tokens[start].keyframesSelectorType = 2; + } else { + return 0; + } + + return i - start; + } + + /** + * Get a single keyframe selector + * @returns {Node} + */ + function getKeyframesSelector() { + var keyframesSelectorType = NodeType.KeyframesSelectorType; + var selectorType = NodeType.SelectorType; + + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + if (token.keyframesSelectorType === 1) { + content.push(getIdent()); + } else { + content.push(getPercentage()); + } + + var keyframesSelector = newNode(keyframesSelectorType, content, line, column); + return newNode(selectorType, [keyframesSelector], line, column); + } + + /** + * Check the keyframe's selector groups + * @param {Number} i + * @returns {Number} + */ + function checkKeyframesSelectorsGroup(i) { + var start = i; + var l = void 0; + + if (l = checkKeyframesSelector(i)) i += l;else return 0; + + while (i < tokensLength) { + var sb = checkSC(i); + var c = checkDelim(i + sb); + if (!c) break; + var sa = checkSC(i + sb + c); + if (l = checkKeyframesSelector(i + sb + c + sa)) i += sb + c + sa + l;else break; + } + + tokens[start].selectorsGroupEnd = i; + + return i - start; + } + + /** + * Get the keyframe's selector groups + * @returns {Array} An array of keyframe selectors + */ + function getKeyframesSelectorsGroup() { + var selectorsGroup = []; + var selectorsGroupEnd = tokens[pos].selectorsGroupEnd; + + selectorsGroup.push(getKeyframesSelector()); + + while (pos < selectorsGroupEnd) { + selectorsGroup = selectorsGroup.concat(getSC()); + selectorsGroup.push(getDelim()); + selectorsGroup = selectorsGroup.concat(getSC()); + selectorsGroup.push(getKeyframesSelector()); + } + + return selectorsGroup; + } + + /** * Check if token is a namespace sign (`|`) * @param {Number} i Token's index number - * @returns {Number} `1` if token is `|`, `0` if not - */function checkNamespace(i){return i < tokensLength && tokens[i].type === TokenType.VerticalLine?1:0;} /** + * @return {Number} `1` if token is `|`, `0` if not + */ + function checkNamespace(i) { + return i < tokensLength && tokens[i].type === TokenType.VerticalLine ? 1 : 0; + } + + /** * Get node with a namespace sign - * @returns {Array} `['namespace']` - */function getNamespace(){var startPos=pos;pos++;var token=tokens[startPos];return newNode(NodeType.NamespaceType,'|',token.ln,token.col);} /** + * @return {Node} + */ + function getNamespace() { + var type = NodeType.NamespaceType; + var token = tokens[pos++]; + var line = token.ln; + var column = token.col; + var content = '|'; + + return newNode(type, content, line, column); + } + + /** * @param {Number} i Token's index number - * @returns {Number} - */function checkNmName2(i){if(tokens[i].type === TokenType.Identifier)return 1;else if(tokens[i].type !== TokenType.DecimalNumber)return 0;i++;return i < tokensLength && tokens[i].type === TokenType.Identifier?2:1;} /** - * @returns {String} - */function getNmName2(){var s=tokens[pos].value;if(tokens[pos++].type === TokenType.DecimalNumber && pos < tokensLength && tokens[pos].type === TokenType.Identifier)s += tokens[pos++].value;return s;} /** + * @return {Number} + */ + function checkNmName2(i) { + if (tokens[i].type === TokenType.Identifier) return 1;else if (tokens[i].type !== TokenType.DecimalNumber) return 0; + + i++; + + return i < tokensLength && tokens[i].type === TokenType.Identifier ? 2 : 1; + } + + /** + * @return {String} + */ + function getNmName2() { + var s = tokens[pos].value; + + if (tokens[pos++].type === TokenType.DecimalNumber && pos < tokensLength && tokens[pos].type === TokenType.Identifier) s += tokens[pos++].value; + + return s; + } + + /** * Check if token is part of a number * @param {Number} i Token's index number - * @returns {Number} Length of number - */function checkNumber(i){if(i >= tokensLength)return 0;if(tokens[i].number_l)return tokens[i].number_l; // `10`: - if(i < tokensLength && tokens[i].type === TokenType.DecimalNumber && (!tokens[i + 1] || tokens[i + 1] && tokens[i + 1].type !== TokenType.FullStop))return tokens[i].number_l = 1,tokens[i].number_l; // `10.`: - if(i < tokensLength && tokens[i].type === TokenType.DecimalNumber && tokens[i + 1] && tokens[i + 1].type === TokenType.FullStop && (!tokens[i + 2] || tokens[i + 2].type !== TokenType.DecimalNumber))return tokens[i].number_l = 2,tokens[i].number_l; // `.10`: - if(i < tokensLength && tokens[i].type === TokenType.FullStop && tokens[i + 1].type === TokenType.DecimalNumber)return tokens[i].number_l = 2,tokens[i].number_l; // `10.10`: - if(i < tokensLength && tokens[i].type === TokenType.DecimalNumber && tokens[i + 1] && tokens[i + 1].type === TokenType.FullStop && tokens[i + 2] && tokens[i + 2].type === TokenType.DecimalNumber)return tokens[i].number_l = 3,tokens[i].number_l;return 0;} /** + * @return {Number} Length of number + */ + function checkNumber(i) { + if (i >= tokensLength) return 0; + + if (tokens[i].number_l) return tokens[i].number_l; + + // `10`: + if (i < tokensLength && tokens[i].type === TokenType.DecimalNumber && (!tokens[i + 1] || tokens[i + 1] && tokens[i + 1].type !== TokenType.FullStop)) { + tokens[i].number_l = 1; + return 1; + } + + // `10.`: + if (i < tokensLength && tokens[i].type === TokenType.DecimalNumber && tokens[i + 1] && tokens[i + 1].type === TokenType.FullStop && (!tokens[i + 2] || tokens[i + 2].type !== TokenType.DecimalNumber)) { + tokens[i].number_l = 2; + return 2; + } + + // `.10`: + if (i < tokensLength && tokens[i].type === TokenType.FullStop && tokens[i + 1].type === TokenType.DecimalNumber) { + tokens[i].number_l = 2; + return 2; + } + + // `10.10`: + if (i < tokensLength && tokens[i].type === TokenType.DecimalNumber && tokens[i + 1] && tokens[i + 1].type === TokenType.FullStop && tokens[i + 2] && tokens[i + 2].type === TokenType.DecimalNumber) { + tokens[i].number_l = 3; + return 3; + } + + return 0; + } + + /** * Get node with number - * @returns {Array} `['number', x]` where `x` is a number converted - * to string. - */function getNumber(){var s='';var startPos=pos;var l=tokens[pos].number_l;for(var j=0;j < l;j++) {s += tokens[pos + j].value;}pos += l;var token=tokens[startPos];return newNode(NodeType.NumberType,s,token.ln,token.col);} /** - * Check if token is an operator (`/`, `%`, `,`, `:` or `=`). + * @return {Node} + */ + function getNumber() { + var type = NodeType.NumberType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = ''; + var l = tokens[pos].number_l; + + for (var j = 0; j < l; j++) { + content += tokens[pos + j].value; + } + + pos += l; + + return newNode(type, content, line, column); + } + + /** + * Check if token is an operator (`/`, `,`, `:` or `=`). * @param {Number} i Token's index number - * @returns {Number} `1` if token is an operator, otherwise `0` - */function checkOperator(i){if(i >= tokensLength)return 0;switch(tokens[i].type){case TokenType.Solidus:case TokenType.PercentSign:case TokenType.Comma:case TokenType.Colon:case TokenType.EqualsSign:case TokenType.EqualitySign:case TokenType.InequalitySign:case TokenType.LessThanSign:case TokenType.GreaterThanSign:case TokenType.Asterisk:return 1;}return 0;} /** + * @return {Number} `1` if token is an operator, otherwise `0` + */ + function checkOperator(i) { + if (i >= tokensLength) return 0; + + switch (tokens[i].type) { + case TokenType.Solidus: + case TokenType.Comma: + case TokenType.Colon: + case TokenType.EqualsSign: + return 1; + } + + return 0; + } + + /** * Get node with an operator - * @returns {Array} `['operator', x]` where `x` is an operator converted - * to string. - */function getOperator(){var startPos=pos;var x=tokens[pos++].value;var token=tokens[startPos];return newNode(NodeType.OperatorType,x,token.ln,token.col);} /** - * Check if token is part of `!optional` word - * @param {Number} i Token's index number - * @returns {Number} - */function checkOptional(i){var start=i;var l=undefined;if(i >= tokensLength || tokens[i++].type !== TokenType.ExclamationMark)return 0;if(l = checkSC(i))i += l;if(tokens[i].value === 'optional'){tokens[start].optionalEnd = i;return i - start + 1;}else {return 0;}} /** - * Get node with `!optional` word - */function getOptional(){var token=tokens[pos];var line=token.ln;var column=token.col;var content=joinValues(pos,token.optionalEnd);pos = token.optionalEnd + 1;return newNode(NodeType.OptionalType,content,line,column);} /** + * @return {Node} + */ + function getOperator() { + var type = NodeType.OperatorType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = token.value; + + pos++; + + return newNode(type, content, line, column); + } + + /** * Check if token is part of text inside parentheses, e.g. `(1)` * @param {Number} i Token's index number * @return {Number} - */function checkParentheses(i){if(i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis)return 0;return tokens[i].right - i + 1;} /** + */ + function checkParentheses(i) { + if (i >= tokensLength) return 0; + + var start = i; + var right = tokens[i].right; + + if (tokens[i].type === TokenType.LeftParenthesis) i++;else return 0; + + if (i < right) { + var l = checkTsets(i); + if (l) i += l;else return 0; + } + + i++; + + return i - start; + } + + /** * Get node with text inside parentheses, e.g. `(1)` * @return {Node} - */function getParentheses(){var type=NodeType.ParenthesesType;var token=tokens[pos];var line=token.ln;var column=token.col;pos++;var tsets=getTsets();var end=getLastPosition(tsets,line,column,1);pos++;return newNode(type,tsets,line,column,end);} /** - * Check if token is a parent selector (`&`). - * @param {Number} i Token's index number - * @returns {Number} - */function checkParentSelector(i){return i < tokensLength && tokens[i].type === TokenType.Ampersand?1:0;} /** - * Get node with a parent selector - */function getParentSelector(){var startPos=pos;pos++;var token=tokens[startPos];return newNode(NodeType.ParentSelectorType,'&',token.ln,token.col);}function checkParentSelectorExtension(i){if(i >= tokensLength)return 0;var start=i;var l=undefined;while(i < tokensLength) {if(l = checkNumber(i) || checkIdentOrInterpolation(i))i += l;else break;}return i - start;}function getParentSelectorExtension(){var type=NodeType.ParentSelectorExtensionType;var token=tokens[pos];var line=token.ln;var column=token.col;var content=[];while(pos < tokensLength) {if(checkNumber(pos))content.push(getNumber());else if(checkIdentOrInterpolation(pos))content = content.concat(getIdentOrInterpolation());else break;}return newNode(type,content,line,column);}function checkParentSelectorWithExtension(i){if(i >= tokensLength)return 0;var start=i;var l=undefined;if(l = checkParentSelector(i))i += l;else return 0;if(l = checkParentSelectorExtension(i))i += l;return i - start;}function getParentSelectorWithExtension(){var content=[getParentSelector()];if(checkParentSelectorExtension(pos))content.push(getParentSelectorExtension());return content;} /** + */ + function getParentheses() { + var type = NodeType.ParenthesesType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var tsets = []; + var right = token.right; + + pos++; + + if (pos < right) { + tsets = getTsets(); + } + + var end = getLastPosition(tsets, line, column, 1); + pos++; + + return newNode(type, tsets, line, column, end); + } + + /** * Check if token is part of a number with percent sign (e.g. `10%`) * @param {Number} i Token's index number - * @returns {Number} - */function checkPercentage(i){var x;if(i >= tokensLength)return 0;x = checkNumber(i);if(!x || i + x >= tokensLength)return 0;return tokens[i + x].type === TokenType.PercentSign?x + 1:0;} /** + * @return {Number} + */ + function checkPercentage(i) { + var x; + + if (i >= tokensLength) return 0; + + x = checkNumber(i); + + if (!x || i + x >= tokensLength) return 0; + + return tokens[i + x].type === TokenType.PercentSign ? x + 1 : 0; + } + + /** * Get node of number with percent sign - * @returns {Array} `['percentage', ['number', x]]` where `x` is a number - * (without percent sign) converted to string. - */function getPercentage(){var startPos=pos;var x=[getNumber()];var token=tokens[startPos];var line=token.ln;var column=token.col;var end=getLastPosition(x,line,column,1);pos++;return newNode(NodeType.PercentageType,x,token.ln,token.col,end);} /** - * Check if token is part of a placeholder selector (e.g. `%abc`). + * @return {Node} + */ + function getPercentage() { + var type = NodeType.PercentageType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = [getNumber()]; + + var end = getLastPosition(content, line, column, 1); + pos++; + + return newNode(type, content, line, column, end); + } + + /** * @param {Number} i Token's index number - * @returns {Number} Length of the selector - */function checkPlaceholder(i){var l;if(i >= tokensLength)return 0;if(tokens[i].placeholder_l)return tokens[i].placeholder_l;if(tokens[i].type === TokenType.PercentSign && (l = checkIdentOrInterpolation(i + 1))){tokens[i].placeholder_l = l + 1;return l + 1;}else return 0;} /** - * Get node with a placeholder selector - * @returns {Array} `['placeholder', ['ident', x]]` where x is a placeholder's - * identifier (without `%`, e.g. `abc`). - */function getPlaceholder(){var startPos=pos;pos++;var x=getIdentOrInterpolation();var token=tokens[startPos];return newNode(NodeType.PlaceholderType,x,token.ln,token.col);} /** - * @param {Number} i Token's index number - * @returns {Number} - */function checkProgid(i){var start=i;var l=undefined;if(i >= tokensLength)return 0;if(joinValues2(i,6) === 'progid:DXImageTransform.Microsoft.')i += 6;else return 0;if(l = checkIdentOrInterpolation(i))i += l;else return 0;if(l = checkSC(i))i += l;if(tokens[i].type === TokenType.LeftParenthesis){tokens[start].progid_end = tokens[i].right;i = tokens[i].right + 1;}else return 0;return i - start;} /** - * @returns {Array} - */function getProgid(){var startPos=pos;var progid_end=tokens[pos].progid_end;var x=joinValues(pos,progid_end);pos = progid_end + 1;var token=tokens[startPos];return newNode(NodeType.ProgidType,x,token.ln,token.col);} /** + * @return {Number} + */ + function checkProgid(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (joinValues2(i, 6) === 'progid:DXImageTransform.Microsoft.') i += 6;else return 0; + + if (l = checkIdent(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (tokens[i].type === TokenType.LeftParenthesis) { + tokens[start].progid_end = tokens[i].right; + i = tokens[i].right + 1; + } else return 0; + + return i - start; + } + + /** + * @return {Node} + */ + function getProgid() { + var type = NodeType.ProgidType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var progid_end = token.progid_end; + var content = joinValues(pos, progid_end); + + pos = progid_end + 1; + + return newNode(type, content, line, column); + } + + /** * Check if token is part of a property * @param {Number} i Token's index number - * @returns {Number} Length of the property - */function checkProperty(i){var start=i;var l=undefined;if(i >= tokensLength)return 0;if(l = checkVariable(i) || checkIdentOrInterpolation(i))i += l;else return 0;return i - start;} /** + * @return {Number} Length of the property + */ + function checkProperty(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkIdent(i)) i += l;else return 0; + + return i - start; + } + + /** * Get node with a property - * @returns {Array} `['property', x]` - */function getProperty(){var startPos=pos;var x=[];if(checkVariable(pos)){x.push(getVariable());}else {x = x.concat(getIdentOrInterpolation());}var token=tokens[startPos];return newNode(NodeType.PropertyType,x,token.ln,token.col);} /** + * @return {Node} + */ + function getProperty() { + var type = NodeType.PropertyType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = [getIdent()]; + + return newNode(type, content, line, column); + } + + /** * Check if token is a colon * @param {Number} i Token's index number - * @returns {Number} `1` if token is a colon, otherwise `0` - */function checkPropertyDelim(i){return i < tokensLength && tokens[i].type === TokenType.Colon?1:0;} /** + * @return {Number} `1` if token is a colon, otherwise `0` + */ + function checkPropertyDelim(i) { + return i < tokensLength && tokens[i].type === TokenType.Colon ? 1 : 0; + } + + /** * Get node with a colon - * @returns {Array} `['propertyDelim']` - */function getPropertyDelim(){var startPos=pos;pos++;var token=tokens[startPos];return newNode(NodeType.PropertyDelimType,':',token.ln,token.col);} /** + * @return {Node} + */ + function getPropertyDelim() { + var type = NodeType.PropertyDelimType; + var token = tokens[pos++]; + var line = token.ln; + var column = token.col; + var content = ':'; + + return newNode(type, content, line, column); + } + + /** * @param {Number} i Token's index number - * @returns {Number} - */function checkPseudo(i){return checkPseudoe(i) || checkPseudoc(i);} /** - * @returns {Array} - */function getPseudo(){if(checkPseudoe(pos))return getPseudoe();if(checkPseudoc(pos))return getPseudoc();} /** + * @return {Number} + */ + function checkPseudo(i) { + return checkPseudoe(i) || checkPseudoc(i); + } + + /** + * @return {Node} + */ + function getPseudo() { + if (checkPseudoe(pos)) return getPseudoe(); + if (checkPseudoc(pos)) return getPseudoc(); + } + + /** * @param {Number} i Token's index number - * @returns {Number} - */function checkPseudoe(i){var l;if(i >= tokensLength || tokens[i++].type !== TokenType.Colon || i >= tokensLength || tokens[i++].type !== TokenType.Colon)return 0;return (l = checkIdentOrInterpolation(i))?l + 2:0;} /** - * @returns {Array} - */function getPseudoe(){var startPos=pos;pos += 2;var x=getIdentOrInterpolation();var token=tokens[startPos];return newNode(NodeType.PseudoeType,x,token.ln,token.col);} /** + * @return {Number} + */ + function checkPseudoe(i) { + var l; + + if (i >= tokensLength || tokens[i++].type !== TokenType.Colon || i >= tokensLength || tokens[i++].type !== TokenType.Colon) return 0; + + return (l = checkIdent(i)) ? l + 2 : 0; + } + + /** + * @return {Node} + */ + function getPseudoe() { + var type = NodeType.PseudoeType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + pos += 2; + + content.push(getIdent()); + + return newNode(type, content, line, column); + } + + /** * @param {Number} i Token's index number - * @returns {Number} - */function checkPseudoc(i){var l;if(i >= tokensLength || tokens[i].type !== TokenType.Colon)return 0;if(l = checkPseudoClass3(i))tokens[i].pseudoClassType = 3;else if(l = checkPseudoClass4(i))tokens[i].pseudoClassType = 4;else if(l = checkPseudoClass5(i))tokens[i].pseudoClassType = 5;else if(l = checkPseudoClass1(i))tokens[i].pseudoClassType = 1;else if(l = checkPseudoClass2(i))tokens[i].pseudoClassType = 2;else if(l = checkPseudoClass6(i))tokens[i].pseudoClassType = 6;else return 0;return l;} /** - * @returns {Array} - */function getPseudoc(){var childType=tokens[pos].pseudoClassType;if(childType === 1)return getPseudoClass1();if(childType === 2)return getPseudoClass2();if(childType === 3)return getPseudoClass3();if(childType === 4)return getPseudoClass4();if(childType === 5)return getPseudoClass5();if(childType === 6)return getPseudoClass6();} /** + * @return {Number} + */ + function checkPseudoc(i) { + var l; + + if (i >= tokensLength || tokens[i].type !== TokenType.Colon) return 0; + + if (l = checkPseudoClass1(i)) tokens[i].pseudoClassType = 1;else if (l = checkPseudoClass2(i)) tokens[i].pseudoClassType = 2;else if (l = checkPseudoClass3(i)) tokens[i].pseudoClassType = 3;else if (l = checkPseudoClass4(i)) tokens[i].pseudoClassType = 4;else if (l = checkPseudoClass5(i)) tokens[i].pseudoClassType = 5;else if (l = checkPseudoClass6(i)) tokens[i].pseudoClassType = 6;else return 0; + + return l; + } + + /** + * @return {Node} + */ + function getPseudoc() { + var childType = tokens[pos].pseudoClassType; + if (childType === 1) return getPseudoClass1(); + if (childType === 2) return getPseudoClass2(); + if (childType === 3) return getPseudoClass3(); + if (childType === 4) return getPseudoClass4(); + if (childType === 5) return getPseudoClass5(); + if (childType === 6) return getPseudoClass6(); + } + + /** + * (1) `:panda(selector)` + * (2) `:panda(selector, selector)` + */ + function checkPseudoClass1(i) { + var start = i; + + // Skip `:`. + i++; + + var l = void 0; + if (l = checkIdent(i)) i += l;else return 0; + + if (i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis) return 0; + + var right = tokens[i].right; + + // Skip `(`. + i++; + + if (l = checkSelectorsGroup(i)) i += l;else return 0; + + if (i !== right) return 0; + + return i - start + 1; + } + + /** * (-) `:not(panda)` - */function checkPseudoClass1(i){var start=i; // Skip `:`. - i++;if(i >= tokensLength)return 0;var l=undefined;if(l = checkIdentOrInterpolation(i))i += l;else return 0;if(i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis)return 0;var right=tokens[i].right; // Skip `(`. - i++;if(l = checkSelectorsGroup(i))i += l;else return 0;if(i !== right)return 0;return right - start + 1;} /** - * (-) `:not(panda)` - */function getPseudoClass1(){var type=NodeType.PseudocType;var token=tokens[pos];var line=token.ln;var column=token.col;var content=[]; // Skip `:`. - pos++;content = content.concat(getIdentOrInterpolation());{var _type=NodeType.ArgumentsType;var _token=tokens[pos];var _line=_token.ln;var _column=_token.col; // Skip `(`. - pos++;var selectors=getSelectorsGroup();var end=getLastPosition(selectors,_line,_column,1);var args=newNode(_type,selectors,_line,_column,end);content.push(args); // Skip `)`. - pos++;}return newNode(type,content,line,column);} /** + */ + function getPseudoClass1() { + var type = NodeType.PseudocType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + // Skip `:`. + pos++; + + content.push(getIdent()); + + { + var _type = NodeType.ArgumentsType; + var _token = tokens[pos]; + var _line = _token.ln; + var _column = _token.col; + + // Skip `(`. + pos++; + + var selectors = getSelectorsGroup(); + var end = getLastPosition(selectors, _line, _column, 1); + var args = newNode(_type, selectors, _line, _column, end); + content.push(args); + + // Skip `)`. + pos++; + } + + return newNode(type, content, line, column); + } + + /** * (1) `:nth-child(odd)` * (2) `:nth-child(even)` * (3) `:lang(de-DE)` - */function checkPseudoClass2(i){var start=i;var l=0; // Skip `:`. - i++;if(i >= tokensLength)return 0;if(l = checkIdentOrInterpolation(i))i += l;else return 0;if(i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis)return 0;var right=tokens[i].right; // Skip `(`. - i++;if(l = checkSC(i))i += l;if(l = checkIdentOrInterpolation(i))i += l;else return 0;if(l = checkSC(i))i += l;if(i !== right)return 0;return i - start + 1;}function getPseudoClass2(){var type=NodeType.PseudocType;var token=tokens[pos];var line=token.ln;var column=token.col;var content=[]; // Skip `:`. - pos++;content = content.concat(getIdentOrInterpolation());var l=tokens[pos].ln;var c=tokens[pos].col;var value=[]; // Skip `(`. - pos++;value = value.concat(getSC()).concat(getIdentOrInterpolation()).concat(getSC());var end=getLastPosition(value,l,c,1);var args=newNode(NodeType.ArgumentsType,value,l,c,end);content.push(args); // Skip `)`. - pos++;return newNode(type,content,line,column);} /** + */ + function checkPseudoClass2(i) { + var start = i; + var l = 0; + + // Skip `:`. + i++; + + if (i >= tokensLength) return 0; + + if (l = checkIdent(i)) i += l;else return 0; + + if (i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis) return 0; + + var right = tokens[i].right; + + // Skip `(`. + i++; + + if (l = checkSC(i)) i += l; + + if (l = checkIdent(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (i !== right) return 0; + + return i - start + 1; + } + + function getPseudoClass2() { + var type = NodeType.PseudocType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + // Skip `:`. + pos++; + + var ident = getIdent(); + content.push(ident); + + // Skip `(`. + pos++; + + var l = tokens[pos].ln; + var c = tokens[pos].col; + var value = []; + + value = value.concat(getSC()); + value.push(getIdent()); + value = value.concat(getSC()); + + var end = getLastPosition(value, l, c, 1); + var args = newNode(NodeType.ArgumentsType, value, l, c, end); + content.push(args); + + // Skip `)`. + pos++; + + return newNode(type, content, line, column); + } + + /** * (-) `:nth-child(-3n + 2)` - */function checkPseudoClass3(i){var start=i;var l=0; // Skip `:`. - i++;if(i >= tokensLength)return 0;if(l = checkIdentOrInterpolation(i))i += l;else return 0;if(i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis)return 0;var right=tokens[i].right; // Skip `(`. - i++;if(l = checkSC(i))i += l;if(l = checkUnary(i))i += l;if(i >= tokensLength)return 0;if(tokens[i].type === TokenType.DecimalNumber)i++;if(i >= tokensLength)return 0;if(tokens[i].value === 'n')i++;else return 0;if(l = checkSC(i))i += l;if(i >= tokensLength)return 0;if(tokens[i].value === '+' || tokens[i].value === '-')i++;else return 0;if(l = checkSC(i))i += l;if(tokens[i].type === TokenType.DecimalNumber)i++;else return 0;if(l = checkSC(i))i += l;if(i !== right)return 0;return i - start + 1;}function getPseudoClass3(){var type=NodeType.PseudocType;var token=tokens[pos];var line=token.ln;var column=token.col; // Skip `:`. - pos++;var content=getIdentOrInterpolation();var l=tokens[pos].ln;var c=tokens[pos].col;var value=[]; // Skip `(`. - pos++;if(checkUnary(pos))value.push(getUnary());if(checkNumber(pos))value.push(getNumber());{var _l=tokens[pos].ln;var _c=tokens[pos].col;var _content=tokens[pos].value;var ident=newNode(NodeType.IdentType,_content,_l,_c);value.push(ident);pos++;}value = value.concat(getSC());if(checkUnary(pos))value.push(getUnary());value = value.concat(getSC());if(checkNumber(pos))value.push(getNumber());value = value.concat(getSC());var end=getLastPosition(value,l,c,1);var args=newNode(NodeType.ArgumentsType,value,l,c,end);content.push(args); // Skip `)`. - pos++;return newNode(type,content,line,column);} /** + */ + function checkPseudoClass3(i) { + var start = i; + var l = 0; + + // Skip `:`. + i++; + + if (i >= tokensLength) return 0; + + if (l = checkIdent(i)) i += l;else return 0; + + if (i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis) return 0; + + var right = tokens[i].right; + + // Skip `(`. + i++; + + if (l = checkSC(i)) i += l; + + if (l = checkUnary(i)) i += l; + if (i >= tokensLength) return 0; + if (tokens[i].type === TokenType.DecimalNumber) i++; + + if (i >= tokensLength) return 0; + if (tokens[i].value === 'n') i++;else return 0; + + if (l = checkSC(i)) i += l; + + if (i >= tokensLength) return 0; + if (tokens[i].value === '+' || tokens[i].value === '-') i++;else return 0; + + if (l = checkSC(i)) i += l; + + if (tokens[i].type === TokenType.DecimalNumber) i++;else return 0; + + if (l = checkSC(i)) i += l; + + if (i !== right) return 0; + + return i - start + 1; + } + + function getPseudoClass3() { + var type = NodeType.PseudocType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + // Skip `:`. + pos++; + + var ident = getIdent(); + content.push(ident); + + var l = tokens[pos].ln; + var c = tokens[pos].col; + var value = []; + + // Skip `(`. + pos++; + + if (checkUnary(pos)) value.push(getUnary()); + if (checkNumber(pos)) value.push(getNumber()); + + { + var _l = tokens[pos].ln; + var _c = tokens[pos].col; + var _content = tokens[pos].value; + var _ident = newNode(NodeType.IdentType, _content, _l, _c); + value.push(_ident); + pos++; + } + + value = value.concat(getSC()); + if (checkUnary(pos)) value.push(getUnary()); + value = value.concat(getSC()); + if (checkNumber(pos)) value.push(getNumber()); + value = value.concat(getSC()); + + var end = getLastPosition(value, l, c, 1); + var args = newNode(NodeType.ArgumentsType, value, l, c, end); + content.push(args); + + // Skip `)`. + pos++; + + return newNode(type, content, line, column); + } + + /** * (-) `:nth-child(-3n)` - */function checkPseudoClass4(i){var start=i;var l=0; // Skip `:`. - i++;if(i >= tokensLength)return 0;if(l = checkIdentOrInterpolation(i))i += l;else return 0;if(i >= tokensLength)return 0;if(tokens[i].type !== TokenType.LeftParenthesis)return 0;var right=tokens[i].right; // Skip `(`. - i++;if(l = checkSC(i))i += l;if(l = checkUnary(i))i += l;if(tokens[i].type === TokenType.DecimalNumber)i++;if(tokens[i].value === 'n')i++;else return 0;if(l = checkSC(i))i += l;if(i !== right)return 0;return i - start + 1;}function getPseudoClass4(){var type=NodeType.PseudocType;var token=tokens[pos];var line=token.ln;var column=token.col; // Skip `:`. - pos++;var content=getIdentOrInterpolation();var l=tokens[pos].ln;var c=tokens[pos].col;var value=[]; // Skip `(`. - pos++;value = value.concat(getSC());if(checkUnary(pos))value.push(getUnary());if(checkNumber(pos))value.push(getNumber());if(checkIdent(pos))value.push(getIdent());value = value.concat(getSC());var end=getLastPosition(value,l,c,1);var args=newNode(NodeType.ArgumentsType,value,l,c,end);content.push(args); // Skip `)`. - pos++;return newNode(type,content,line,column);} /** + */ + function checkPseudoClass4(i) { + var start = i; + var l = 0; + + // Skip `:`. + i++; + + if (i >= tokensLength) return 0; + + if (l = checkIdent(i)) i += l;else return 0; + + if (i >= tokensLength) return 0; + if (tokens[i].type !== TokenType.LeftParenthesis) return 0; + + var right = tokens[i].right; + + // Skip `(`. + i++; + + if (l = checkSC(i)) i += l; + + if (l = checkUnary(i)) i += l; + if (tokens[i].type === TokenType.DecimalNumber) i++; + + if (tokens[i].value === 'n') i++;else return 0; + + if (l = checkSC(i)) i += l; + + if (i !== right) return 0; + + return i - start + 1; + } + + function getPseudoClass4() { + var type = NodeType.PseudocType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + // Skip `:`. + pos++; + + var ident = getIdent(); + content.push(ident); + + // Skip `(`. + pos++; + + var l = tokens[pos].ln; + var c = tokens[pos].col; + var value = []; + + if (checkUnary(pos)) value.push(getUnary()); + if (checkNumber(pos)) value.push(getNumber()); + if (checkIdent(pos)) value.push(getIdent()); + value = value.concat(getSC()); + + var end = getLastPosition(value, l, c, 1); + var args = newNode(NodeType.ArgumentsType, value, l, c, end); + content.push(args); + + // Skip `)`. + pos++; + + return newNode(type, content, line, column); + } + + /** * (-) `:nth-child(+8)` - */function checkPseudoClass5(i){var start=i;var l=0; // Skip `:`. - i++;if(i >= tokensLength)return 0;if(l = checkIdentOrInterpolation(i))i += l;else return 0;if(i >= tokensLength)return 0;if(tokens[i].type !== TokenType.LeftParenthesis)return 0;var right=tokens[i].right; // Skip `(`. - i++;if(l = checkSC(i))i += l;if(l = checkUnary(i))i += l;if(tokens[i].type === TokenType.DecimalNumber)i++;else return 0;if(l = checkSC(i))i += l;if(i !== right)return 0;return i - start + 1;}function getPseudoClass5(){var type=NodeType.PseudocType;var token=tokens[pos];var line=token.ln;var column=token.col; // Skip `:`. - pos++;var content=getIdentOrInterpolation();var l=tokens[pos].ln;var c=tokens[pos].col;var value=[]; // Skip `(`. - pos++;if(checkUnary(pos))value.push(getUnary());if(checkNumber(pos))value.push(getNumber());value = value.concat(getSC());var end=getLastPosition(value,l,c,1);var args=newNode(NodeType.ArgumentsType,value,l,c,end);content.push(args); // Skip `)`. - pos++;return newNode(type,content,line,column);} /** + */ + function checkPseudoClass5(i) { + var start = i; + var l = 0; + + // Skip `:`. + i++; + + if (i >= tokensLength) return 0; + + if (l = checkIdent(i)) i += l;else return 0; + + if (i >= tokensLength) return 0; + if (tokens[i].type !== TokenType.LeftParenthesis) return 0; + + var right = tokens[i].right; + + // Skip `(`. + i++; + + if (l = checkSC(i)) i += l; + + if (l = checkUnary(i)) i += l; + if (tokens[i].type === TokenType.DecimalNumber) i++;else return 0; + + if (l = checkSC(i)) i += l; + + if (i !== right) return 0; + + return i - start + 1; + } + + function getPseudoClass5() { + var type = NodeType.PseudocType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + // Skip `:`. + pos++; + + var ident = getIdent(); + content.push(ident); + + // Skip `(`. + pos++; + + var l = tokens[pos].ln; + var c = tokens[pos].col; + var value = []; + + if (checkUnary(pos)) value.push(getUnary()); + if (checkNumber(pos)) value.push(getNumber()); + value = value.concat(getSC()); + + var end = getLastPosition(value, l, c, 1); + var args = newNode(NodeType.ArgumentsType, value, l, c, end); + content.push(args); + + // Skip `)`. + pos++; + + return newNode(type, content, line, column); + } + + /** * (-) `:checked` - */function checkPseudoClass6(i){var start=i;var l=0; // Skip `:`. - i++;if(i >= tokensLength)return 0;if(l = checkIdentOrInterpolation(i))i += l;else return 0;return i - start;}function getPseudoClass6(){var type=NodeType.PseudocType;var token=tokens[pos];var line=token.ln;var column=token.col; // Skip `:`. - pos++;var content=getIdentOrInterpolation();return newNode(type,content,line,column);} /** + */ + function checkPseudoClass6(i) { + var start = i; + var l = 0; + + // Skip `:`. + i++; + + if (i >= tokensLength) return 0; + + if (l = checkIdent(i)) i += l;else return 0; + + return i - start; + } + + function getPseudoClass6() { + var type = NodeType.PseudocType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + // Skip `:`. + pos++; + + var ident = getIdent(); + content.push(ident); + + return newNode(type, content, line, column); + } + + /** * @param {Number} i Token's index number - * @returns {Number} - */function checkRuleset(i){var start=i;var l=undefined;if(i >= tokensLength)return 0;if(l = checkSelectorsGroup(i))i += l;else return 0;if(l = checkSC(i))i += l;if(l = checkBlock(i))i += l;else return 0;return i - start;}function getRuleset(){var type=NodeType.RulesetType;var token=tokens[pos];var line=token.ln;var column=token.col;var content=[];content = content.concat(getSelectorsGroup());content = content.concat(getSC());content.push(getBlock());return newNode(type,content,line,column);} /** + * @return {Number} + */ + function checkRuleset(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkSelectorsGroup(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkBlock(i)) i += l;else return 0; + + return i - start; + } + + /** + * @return {Node} + */ + function getRuleset() { + var type = NodeType.RulesetType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + content = content.concat(getSelectorsGroup()); + content = content.concat(getSC()); + content.push(getBlock()); + + return newNode(type, content, line, column); + } + + /** * Check if token is marked as a space (if it's a space or a tab * or a line break). * @param {Number} i - * @returns {Number} Number of spaces in a row starting with the given token. - */function checkS(i){return i < tokensLength && tokens[i].ws?tokens[i].ws_last - i + 1:0;} /** + * @return {Number} Number of spaces in a row starting with the given token. + */ + function checkS(i) { + return i < tokensLength && tokens[i].ws ? tokens[i].ws_last - i + 1 : 0; + } + + /** * Get node with spaces - * @returns {Array} `['s', x]` where `x` is a string containing spaces - */function getS(){var startPos=pos;var x=joinValues(pos,tokens[pos].ws_last);pos = tokens[pos].ws_last + 1;var token=tokens[startPos];return newNode(NodeType.SType,x,token.ln,token.col);} /** + * @return {Node} + */ + function getS() { + var type = NodeType.SType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = joinValues(pos, tokens[pos].ws_last); + + pos = tokens[pos].ws_last + 1; + + return newNode(type, content, line, column); + } + + /** * Check if token is a space or a comment. * @param {Number} i Token's index number - * @returns {Number} Number of similar (space or comment) tokens + * @return {Number} Number of similar (space or comment) tokens * in a row starting with the given token. - */function checkSC(i){if(i >= tokensLength)return 0;var l=undefined;var lsc=0;while(i < tokensLength) {if(!(l = checkS(i)) && !(l = checkCommentML(i)) && !(l = checkCommentSL(i)))break;i += l;lsc += l;}return lsc || 0;} /** + */ + function checkSC(i) { + var l = void 0; + var lsc = 0; + + while (i < tokensLength) { + if (l = checkS(i)) tokens[i].sc_child = 1;else if (l = checkCommentML(i)) tokens[i].sc_child = 2;else break; + i += l; + lsc += l; + } + + return lsc || 0; + } + + /** * Get node with spaces and comments - * @returns {Array} Array containing nodes with spaces (if there are any) - * and nodes with comments (if there are any): - * `[['s', x]*, ['comment', y]*]` where `x` is a string of spaces - * and `y` is a comment's text (without `/*` and `* /`). - */function getSC(){var sc=[];if(pos >= tokensLength)return sc;while(pos < tokensLength) {if(checkS(pos))sc.push(getS());else if(checkCommentML(pos))sc.push(getCommentML());else if(checkCommentSL(pos))sc.push(getCommentSL());else break;}return sc;} /** + * @return {Array} + */ + function getSC() { + var sc = []; + + if (pos >= tokensLength) return sc; + + while (pos < tokensLength) { + var childType = tokens[pos].sc_child; + if (childType === 1) sc.push(getS());else if (childType === 2) sc.push(getCommentML());else break; + } + + return sc; + } + + /** * Check if token is part of a hexadecimal number (e.g. `#fff`) inside * a simple selector * @param {Number} i Token's index number - * @returns {Number} - */function checkShash(i){var l;if(i >= tokensLength || tokens[i].type !== TokenType.NumberSign)return 0;return (l = checkIdentOrInterpolation(i + 1))?l + 1:0;} /** + * @return {Number} + */ + function checkShash(i) { + var l; + + if (i >= tokensLength || tokens[i].type !== TokenType.NumberSign) return 0; + + return (l = checkIdent(i + 1)) ? l + 1 : 0; + } + + /** * Get node with a hexadecimal number (e.g. `#fff`) inside a simple * selector - * @returns {Array} `['shash', x]` where `x` is a hexadecimal number - * converted to string (without `#`, e.g. `fff`) - */function getShash(){var startPos=pos;var token=tokens[startPos];pos++;var x=getIdentOrInterpolation();return newNode(NodeType.ShashType,x,token.ln,token.col);} /** + * @return {Node} + */ + function getShash() { + var type = NodeType.ShashType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + pos++; + + var ident = getIdent(); + content.push(ident); + + return newNode(type, content, line, column); + } + + /** * Check if token is part of a string (text wrapped in quotes) * @param {Number} i Token's index number - * @returns {Number} `1` if token is part of a string, `0` if not - */function checkString(i){return i < tokensLength && (tokens[i].type === TokenType.StringSQ || tokens[i].type === TokenType.StringDQ)?1:0;} /** + * @return {Number} `1` if token is part of a string, `0` if not + */ + function checkString(i) { + if (i >= tokensLength) { + return 0; + } + + if (tokens[i].type === TokenType.StringSQ || tokens[i].type === TokenType.StringDQ) { + return 1; + } + + return 0; + } + + /** * Get string's node - * @returns {Array} `['string', x]` where `x` is a string (including + * @return {Array} `['string', x]` where `x` is a string (including * quotes). - */function getString(){var startPos=pos;var x=tokens[pos++].value;var token=tokens[startPos];return newNode(NodeType.StringType,x,token.ln,token.col);} /** + */ + function getString() { + var type = NodeType.StringType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = token.value; + + pos++; + + return newNode(type, content, line, column); + } + + /** * Validate stylesheet: it should consist of any number (0 or more) of * rulesets (sets of rules with selectors), @-rules, whitespaces or * comments. * @param {Number} i Token's index number - * @returns {Number} - */function checkStylesheet(i){var start=i;var l=undefined;while(i < tokensLength) {if(l = checkSC(i) || checkDeclaration(i) || checkDeclDelim(i) || checkInclude(i) || checkExtend(i) || checkMixin(i) || checkLoop(i) || checkConditionalStatement(i) || checkAtrule(i) || checkRuleset(i))i += l;else throwError(i);}return i - start;} /** - * @returns {Array} `['stylesheet', x]` where `x` is all stylesheet's + * @return {Number} + */ + function checkStylesheet(i) { + var start = i; + var l = void 0; + + // Check every token: + while (i < tokensLength) { + if (l = checkSC(i)) tokens[i].stylesheet_child = 1;else if (l = checkRuleset(i)) tokens[i].stylesheet_child = 2;else if (l = checkAtrule(i)) tokens[i].stylesheet_child = 3;else if (l = checkDeclDelim(i)) tokens[i].stylesheet_child = 4;else throwError(i); + + i += l; + } + + return i - start; + } + + /** + * @return {Array} `['stylesheet', x]` where `x` is all stylesheet's * nodes. - */function getStylesheet(){var startPos=pos;var x=[];while(pos < tokensLength) {if(checkSC(pos))x = x.concat(getSC());else if(checkRuleset(pos))x.push(getRuleset());else if(checkInclude(pos))x.push(getInclude());else if(checkExtend(pos))x.push(getExtend());else if(checkMixin(pos))x.push(getMixin());else if(checkLoop(pos))x.push(getLoop());else if(checkConditionalStatement(pos))x.push(getConditionalStatement());else if(checkAtrule(pos))x.push(getAtrule());else if(checkDeclaration(pos))x.push(getDeclaration());else if(checkDeclDelim(pos))x.push(getDeclDelim());else throwError();}var token=tokens[startPos];return newNode(NodeType.StylesheetType,x,token.ln,token.col);} /** + */ + function getStylesheet() { + var type = NodeType.StylesheetType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + var childType = void 0; + + while (pos < tokensLength) { + childType = tokens[pos].stylesheet_child; + if (childType === 1) content = content.concat(getSC());else if (childType === 2) content.push(getRuleset());else if (childType === 3) content.push(getAtrule());else if (childType === 4) content.push(getDeclDelim()); + } + + return newNode(type, content, line, column); + } + + /** * @param {Number} i Token's index number - * @returns {Number} - */function checkTset(i){return checkVhash(i) || checkOperator(i) || checkAny(i) || checkSC(i) || checkInterpolation(i);} /** - * @returns {Array} - */function getTset(){if(checkVhash(pos))return getVhash();else if(checkOperator(pos))return getOperator();else if(checkAny(pos))return getAny();else if(checkSC(pos))return getSC();else if(checkInterpolation(pos))return getInterpolation();} /** + * @return {Number} + */ + function checkTset(i) { + var l; + + if (l = checkVhash(i)) tokens[i].tset_child = 1;else if (l = checkAny(i)) tokens[i].tset_child = 2;else if (l = checkSC(i)) tokens[i].tset_child = 3;else if (l = checkOperator(i)) tokens[i].tset_child = 4; + + return l; + } + + /** + * @return {Array} + */ + function getTset() { + var childType = tokens[pos].tset_child; + if (childType === 1) return getVhash();else if (childType === 2) return getAny();else if (childType === 3) return getSC();else if (childType === 4) return getOperator(); + } + + /** * @param {Number} i Token's index number - * @returns {Number} - */function checkTsets(i){var start=i;var l=undefined;if(i >= tokensLength)return 0;while(l = checkTset(i)) {i += l;}return i - start;} /** - * @returns {Array} - */function getTsets(){var x=[];var t=undefined;while(t = getTset()) {if(typeof t.content === 'string')x.push(t);else x = x.concat(t);}return x;} /** + * @return {Number} + */ + function checkTsets(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + while (l = checkTset(i)) { + i += l; + } + + return i - start; + } + + /** + * @return {Array} + */ + function getTsets() { + var x = []; + var t = void 0; + + while (checkTset(pos)) { + t = getTset(); + if (typeof t.content === 'string') x.push(t);else x = x.concat(t); + } + + return x; + } + + /** * Check if token is an unary (arithmetical) sign (`+` or `-`) * @param {Number} i Token's index number - * @returns {Number} `1` if token is an unary sign, `0` if not - */function checkUnary(i){return i < tokensLength && (tokens[i].type === TokenType.HyphenMinus || tokens[i].type === TokenType.PlusSign)?1:0;} /** + * @return {Number} `1` if token is an unary sign, `0` if not + */ + function checkUnary(i) { + if (i >= tokensLength) { + return 0; + } + + if (tokens[i].type === TokenType.HyphenMinus || tokens[i].type === TokenType.PlusSign) { + return 1; + } + + return 0; + } + + /** * Get node with an unary (arithmetical) sign (`+` or `-`) - * @returns {Array} `['unary', x]` where `x` is an unary sign + * @return {Array} `['unary', x]` where `x` is an unary sign * converted to string. - */function getUnary(){var startPos=pos;var x=tokens[pos++].value;var token=tokens[startPos];return newNode(NodeType.OperatorType,x,token.ln,token.col);} /** + */ + function getUnary() { + var type = NodeType.OperatorType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = token.value; + + pos++; + + return newNode(type, content, line, column); + } + + /** + * Check if token is a unicode range (single or multiple <urange> nodes) + * @param {number} i Token's index + * @return {number} Unicode range node's length + */ + function checkUnicodeRange(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkUrange(i)) i += l;else return 0; + + while (i < tokensLength) { + var spaceBefore = checkSC(i); + var comma = checkDelim(i + spaceBefore); + if (!comma) break; + + var spaceAfter = checkSC(i + spaceBefore + comma); + if (l = checkUrange(i + spaceBefore + comma + spaceAfter)) { + i += spaceBefore + comma + spaceAfter + l; + } else break; + } + + return i - start; + } + + /** + * Get a unicode range node + * @return {Node} + */ + function getUnicodeRange() { + var type = NodeType.UnicodeRangeType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + while (pos < tokensLength) { + if (checkSC(pos)) content = content.concat(getSC());else if (checkDelim(pos)) content.push(getDelim());else if (checkUrange(pos)) content.push(getUrange());else break; + } + + return newNode(type, content, line, column); + } + + /** + * Check if token is a u-range (part of a unicode-range) + * (1) `U+416` + * (2) `U+400-4ff` + * (3) `U+4??` + * @param {number} i Token's index + * @return {number} Urange node's length + */ + function checkUrange(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + // Check for unicode prefix (u+ or U+) + if (tokens[i].value === 'U' || tokens[i].value === 'u') i += 1;else return 0; + + if (i >= tokensLength) return 0; + + if (tokens[i].value === '+') i += 1;else return 0; + + while (i < tokensLength) { + if (l = checkIdent(i)) i += l;else if (l = checkNumber(i)) i += l;else if (l = checkUnary(i)) i += l;else if (l = _checkUnicodeWildcard(i)) i += l;else break; + } + + tokens[start].urangeEnd = i - 1; + + return i - start; + } + + /** + * Get a u-range node (part of a unicode-range) + * @return {Node} + */ + function getUrange() { + var startPos = pos; + var type = NodeType.UrangeType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + content = joinValues(startPos, tokens[startPos].urangeEnd); + pos = tokens[startPos].urangeEnd + 1; + + return newNode(type, content, line, column); + } + + /** + * Check for unicode wildcard characters `?` + * @param {number} i Token's index + * @return {number} Wildcard length + */ + function _checkUnicodeWildcard(i) { + var start = i; + + if (i >= tokensLength) return 0; + + while (i < tokensLength) { + if (tokens[i].type === TokenType.QuestionMark) i += 1;else break; + } + + return i - start; + } + + /** * Check if token is part of URI (e.g. `url('/css/styles.css')`) * @param {Number} i Token's index number - * @returns {Number} Length of URI - */function checkUri(i){var start=i;if(i >= tokensLength || tokens[i++].value !== 'url' || i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis)return 0;return tokens[i].right - start + 1;} /** + * @return {Number} Length of URI + */ + function checkUri(i) { + var start = i; + + if (i >= tokensLength || tokens[i].value !== 'url') return 0; + i += 1; + if (i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis) return 0; + + return tokens[i].right - start + 1; + } + + /** * Get node with URI - * @returns {Array} `['uri', x]` where `x` is URI's nodes (without `url` + * @return {Array} `['uri', x]` where `x` is URI's nodes (without `url` * and braces, e.g. `['string', ''/css/styles.css'']`). - */function getUri(){var startPos=pos;var uriExcluding={};var uri=undefined;var token=undefined;var l=undefined;var raw=undefined;pos += 2;uriExcluding[TokenType.Space] = 1;uriExcluding[TokenType.Tab] = 1;uriExcluding[TokenType.Newline] = 1;uriExcluding[TokenType.LeftParenthesis] = 1;uriExcluding[TokenType.RightParenthesis] = 1;if(checkUriContent(pos)){uri = [].concat(getSC()).concat(getUriContent()).concat(getSC());}else {uri = [].concat(getSC());l = checkExcluding(uriExcluding,pos);token = tokens[pos];raw = newNode(NodeType.RawType,joinValues(pos,pos + l),token.ln,token.col);uri.push(raw);pos += l + 1;uri = uri.concat(getSC());}token = tokens[startPos];var line=token.ln;var column=token.col;var end=getLastPosition(uri,line,column,1);pos++;return newNode(NodeType.UriType,uri,token.ln,token.col,end);} /** + */ + function getUri() { + var startPos = pos; + var uriExcluding = {}; + var uri = void 0; + var l = void 0; + var raw = void 0; + + var rawContent = void 0; + var t = void 0; + + pos += 2; + + uriExcluding[TokenType.Space] = 1; + uriExcluding[TokenType.Tab] = 1; + uriExcluding[TokenType.Newline] = 1; + uriExcluding[TokenType.LeftParenthesis] = 1; + uriExcluding[TokenType.RightParenthesis] = 1; + + if (checkUri1(pos)) { + uri = [].concat(getSC()).concat([getString()]).concat(getSC()); + } else { + uri = checkSC(pos) ? getSC() : []; + l = checkExcluding(uriExcluding, pos); + rawContent = joinValues(pos, pos + l); + t = tokens[pos]; + raw = newNode(NodeType.RawType, rawContent, t.ln, t.col); + + uri.push(raw); + + pos += l + 1; + + if (checkSC(pos)) uri = uri.concat(getSC()); + } + + t = tokens[startPos]; + var line = t.ln; + var column = t.col; + var end = getLastPosition(uri, line, column, 1); + pos++; + + return newNode(NodeType.UriType, uri, line, column, end); + } + + /** * @param {Number} i Token's index number - * @returns {Number} - */function checkUriContent(i){return checkUri1(i) || checkFunction(i);} /** - * @returns {Array} - */function getUriContent(){if(checkUri1(pos))return getString();else if(checkFunction(pos))return getFunction();} /** - * @param {Number} i Token's index number - * @returns {Number} - */function checkUri1(i){var start=i;var l=undefined;if(i >= tokensLength)return 0;if(l = checkSC(i))i += l;if(tokens[i].type !== TokenType.StringDQ && tokens[i].type !== TokenType.StringSQ)return 0;i++;if(l = checkSC(i))i += l;return i - start;} /** + * @return {Number} + */ + function checkUri1(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkSC(i)) i += l; + + if (tokens[i].type !== TokenType.StringDQ && tokens[i].type !== TokenType.StringSQ) return 0; + + i++; + + if (l = checkSC(i)) i += l; + + return i - start; + } + + /** * Check if token is part of a value * @param {Number} i Token's index number - * @returns {Number} Length of the value - */function checkValue(i){var start=i;var l=undefined;var s=undefined;var _i=undefined;while(i < tokensLength) {if(checkDeclDelim(i))break;s = checkSC(i);_i = i + s;if(l = _checkValue(_i))i += l + s;if(!l || checkBlock(i - l))break;}return i - start;} /** + * @return {Number} Length of the value + */ + function checkValue(i) { + var start = i; + var l = void 0; + var s = void 0; + var _i = void 0; + + while (i < tokensLength) { + s = checkSC(i); + _i = i + s; + + if (l = _checkValue(_i)) i += l + s;else break; + } + + tokens[start].value_end = i; + return i - start; + } + + /** + * @return {Array} + */ + function getValue() { + var startPos = pos; + var end = tokens[pos].value_end; + var x = []; + + while (pos < end) { + if (tokens[pos].value_child) x.push(_getValue());else x = x.concat(getSC()); + } + + var t = tokens[startPos]; + return newNode(NodeType.ValueType, x, t.ln, t.col); + } + + /** * @param {Number} i Token's index number - * @returns {Number} - */function _checkValue(i){return checkInterpolation(i) || checkVariable(i) || checkVhash(i) || checkBlock(i) || checkAtkeyword(i) || checkOperator(i) || checkImportant(i) || checkGlobal(i) || checkDefault(i) || checkProgid(i) || checkAny(i);} /** - * @returns {Array} - */function getValue(){var startPos=pos;var x=[];var _pos=undefined;var s=undefined;while(pos < tokensLength) {s = checkSC(pos);_pos = pos + s;if(checkDeclDelim(_pos))break;if(!_checkValue(_pos))break;if(s)x = x.concat(getSC());x.push(_getValue());if(checkBlock(_pos))break;}var token=tokens[startPos];return newNode(NodeType.ValueType,x,token.ln,token.col);} /** - * @returns {Array} - */function _getValue(){if(checkInterpolation(pos))return getInterpolation();else if(checkVariable(pos))return getVariable();else if(checkVhash(pos))return getVhash();else if(checkBlock(pos))return getBlock();else if(checkAtkeyword(pos))return getAtkeyword();else if(checkOperator(pos))return getOperator();else if(checkImportant(pos))return getImportant();else if(checkGlobal(pos))return getGlobal();else if(checkDefault(pos))return getDefault();else if(checkProgid(pos))return getProgid();else if(checkAny(pos))return getAny();} /** - * Check if token is part of a variable - * @param {Number} i Token's index number - * @returns {Number} Length of the variable - */function checkVariable(i){var l;if(i >= tokensLength || tokens[i].type !== TokenType.DollarSign)return 0;return (l = checkIdent(i + 1))?l + 1:0;} /** - * Get node with a variable - * @returns {Array} `['variable', ['ident', x]]` where `x` is - * a variable name. - */function getVariable(){var startPos=pos;var x=[];pos++;x.push(getIdent());var token=tokens[startPos];return newNode(NodeType.VariableType,x,token.ln,token.col);} /** - * Check if token is part of a variables list (e.g. `$values...`). - * @param {Number} i Token's index number - * @returns {Number} - */function checkVariablesList(i){var d=0; // Number of dots - var l=undefined;if(i >= tokensLength)return 0;if(l = checkVariable(i))i += l;else return 0;while(i < tokensLength && tokens[i].type === TokenType.FullStop) {d++;i++;}return d === 3?l + d:0;} /** - * Get node with a variables list - * @returns {Array} `['variableslist', ['variable', ['ident', x]]]` where - * `x` is a variable name. - */function getVariablesList(){var startPos=pos;var x=getVariable();var token=tokens[startPos];var line=token.ln;var column=token.col;var end=getLastPosition([x],line,column,3);pos += 3;return newNode(NodeType.VariablesListType,[x],token.ln,token.col,end);} /** + * @return {Number} + */ + function _checkValue(i) { + var l; + + if (l = checkProgid(i)) tokens[i].value_child = 1;else if (l = checkVhash(i)) tokens[i].value_child = 2;else if (l = checkAny(i)) tokens[i].value_child = 3;else if (l = checkOperator(i)) tokens[i].value_child = 4;else if (l = checkImportant(i)) tokens[i].value_child = 5; + + return l; + } + + /** + * @return {Array} + */ + function _getValue() { + var childType = tokens[pos].value_child; + if (childType === 1) return getProgid();else if (childType === 2) return getVhash();else if (childType === 3) return getAny();else if (childType === 4) return getOperator();else if (childType === 5) return getImportant(); + } + + /** * Check if token is part of a hexadecimal number (e.g. `#fff`) inside * some value * @param {Number} i Token's index number - * @returns {Number} - */function checkVhash(i){var l;if(i >= tokensLength || tokens[i].type !== TokenType.NumberSign)return 0;return (l = checkNmName2(i + 1))?l + 1:0;} /** + * @return {Number} + */ + function checkVhash(i) { + var l; + + if (i >= tokensLength || tokens[i].type !== TokenType.NumberSign) return 0; + + return (l = checkNmName2(i + 1)) ? l + 1 : 0; + } + + /** * Get node with a hexadecimal number (e.g. `#fff`) inside some value - * @returns {Array} `['vhash', x]` where `x` is a hexadecimal number + * @return {Array} `['vhash', x]` where `x` is a hexadecimal number * converted to string (without `#`, e.g. `'fff'`). - */function getVhash(){var startPos=pos;var x=undefined;var token=tokens[startPos];var line=token.ln;var column=token.col;pos++;x = getNmName2();var end=getLastPosition(x,line,column + 1);return newNode(NodeType.VhashType,x,token.ln,token.col,end);}module.exports = function(_tokens,context){tokens = _tokens;tokensLength = tokens.length;pos = 0;return contexts[context]();};function checkSelectorsGroup(i){if(i >= tokensLength)return 0;var start=i;var l=undefined;if(l = checkSelector(i))i += l;else return 0;while(i < tokensLength) {var sb=checkSC(i);var c=checkDelim(i + sb);if(!c)break;var sa=checkSC(i + sb + c);if(l = checkSelector(i + sb + c + sa))i += sb + c + sa + l;else break;}tokens[start].selectorsGroupEnd = i;return i - start;}function getSelectorsGroup(){var selectorsGroup=[];var selectorsGroupEnd=tokens[pos].selectorsGroupEnd;selectorsGroup.push(getSelector());while(pos < selectorsGroupEnd) {selectorsGroup = selectorsGroup.concat(getSC());selectorsGroup.push(getDelim());selectorsGroup = selectorsGroup.concat(getSC());selectorsGroup.push(getSelector());}return selectorsGroup;}function checkSelector(i){var l;if(l = checkSelector1(i))tokens[i].selectorType = 1;else if(l = checkSelector2(i))tokens[i].selectorType = 2;return l;}function getSelector(){var selectorType=tokens[pos].selectorType;if(selectorType === 1)return getSelector1();else return getSelector2();} /** - * Checks for selector which starts with a compound selector. - */function checkSelector1(i){if(i >= tokensLength)return 0;var start=i;var l=undefined;if(l = checkCompoundSelector(i))i += l;else return 0;while(i < tokensLength) {var s=checkSC(i);var c=checkCombinator(i + s);if(!s && !c)break;if(c){i += s + c;s = checkSC(i);}if(l = checkCompoundSelector(i + s))i += s + l;else break;}tokens[start].selectorEnd = i;return i - start;}function getSelector1(){var type=NodeType.SelectorType;var token=tokens[pos];var line=token.ln;var column=token.col;var selectorEnd=token.selectorEnd;var content=getCompoundSelector();while(pos < selectorEnd) {if(checkSC(pos))content = content.concat(getSC());else if(checkCombinator(pos))content.push(getCombinator());else if(checkCompoundSelector(pos))content = content.concat(getCompoundSelector());}return newNode(type,content,line,column);} /** - * Checks for a selector that starts with a combinator. - */function checkSelector2(i){if(i >= tokensLength)return 0;var start=i;var l=undefined;if(l = checkCombinator(i))i += l;else return 0;while(i < tokensLength) {var sb=checkSC(i);if(l = checkCompoundSelector(i + sb))i += sb + l;else break;var sa=checkSC(i);var c=checkCombinator(i + sa);if(!sa && !c)break;if(c){i += sa + c;}}tokens[start].selectorEnd = i;return i - start;}function getSelector2(){var type=NodeType.SelectorType;var token=tokens[pos];var line=token.ln;var column=token.col;var selectorEnd=token.selectorEnd;var content=[getCombinator()];while(pos < selectorEnd) {if(checkSC(pos))content = content.concat(getSC());else if(checkCombinator(pos))content.push(getCombinator());else if(checkCompoundSelector(pos))content = content.concat(getCompoundSelector());}return newNode(type,content,line,column);}function checkCompoundSelector(i){var l=undefined;if(l = checkCompoundSelector1(i)){tokens[i].compoundSelectorType = 1;}else if(l = checkCompoundSelector2(i)){tokens[i].compoundSelectorType = 2;}return l;}function getCompoundSelector(){var type=tokens[pos].compoundSelectorType;if(type === 1)return getCompoundSelector1();if(type === 2)return getCompoundSelector2();}function checkCompoundSelector1(i){if(i >= tokensLength)return 0;var start=i;var l=undefined;if(l = checkTypeSelector(i) || checkPlaceholder(i) || checkParentSelectorWithExtension(i))i += l;else return 0;while(i < tokensLength) {var _l2=checkShash(i) || checkClass(i) || checkAttributeSelector(i) || checkPseudo(i) || checkPlaceholder(i);if(_l2)i += _l2;else break;}tokens[start].compoundSelectorEnd = i;return i - start;}function getCompoundSelector1(){var sequence=[];var compoundSelectorEnd=tokens[pos].compoundSelectorEnd;if(checkTypeSelector(pos))sequence.push(getTypeSelector());else if(checkPlaceholder(pos))sequence.push(getPlaceholder());else if(checkParentSelectorWithExtension(pos))sequence = sequence.concat(getParentSelectorWithExtension());while(pos < compoundSelectorEnd) {if(checkShash(pos))sequence.push(getShash());else if(checkClass(pos))sequence.push(getClass());else if(checkAttributeSelector(pos))sequence.push(getAttributeSelector());else if(checkPseudo(pos))sequence.push(getPseudo());else if(checkPlaceholder(pos))sequence.push(getPlaceholder());}return sequence;}function checkCompoundSelector2(i){if(i >= tokensLength)return 0;var start=i;while(i < tokensLength) {var l=checkShash(i) || checkClass(i) || checkAttributeSelector(i) || checkPseudo(i) || checkPlaceholder(i);if(l)i += l;else break;}tokens[start].compoundSelectorEnd = i;return i - start;}function getCompoundSelector2(){var sequence=[];var compoundSelectorEnd=tokens[pos].compoundSelectorEnd;while(pos < compoundSelectorEnd) {if(checkShash(pos))sequence.push(getShash());else if(checkClass(pos))sequence.push(getClass());else if(checkAttributeSelector(pos))sequence.push(getAttributeSelector());else if(checkPseudo(pos))sequence.push(getPseudo());else if(checkPlaceholder(pos))sequence.push(getPlaceholder());}return sequence;}function checkTypeSelector(i){if(i >= tokensLength)return 0;var start=i;var l=undefined;if(l = checkNamePrefix(i))i += l;if(tokens[i].type === TokenType.Asterisk)i++;else if(l = checkIdentOrInterpolation(i))i += l;else return 0;return i - start;}function getTypeSelector(){var type=NodeType.TypeSelectorType;var token=tokens[pos];var line=token.ln;var column=token.col;var content=[];if(checkNamePrefix(pos))content.push(getNamePrefix());if(checkIdentOrInterpolation(pos))content = content.concat(getIdentOrInterpolation());return newNode(type,content,line,column);}function checkAttributeSelector(i){var l=undefined;if(l = checkAttributeSelector1(i))tokens[i].attributeSelectorType = 1;else if(l = checkAttributeSelector2(i))tokens[i].attributeSelectorType = 2;return l;}function getAttributeSelector(){var type=tokens[pos].attributeSelectorType;if(type === 1)return getAttributeSelector1();else return getAttributeSelector2();} /** + */ + function getVhash() { + var type = NodeType.VhashType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = void 0; + + pos++; + + content = getNmName2(); + var end = getLastPosition(content, line, column + 1); + return newNode(type, content, line, column, end); + } + + function checkSelectorsGroup(i) { + if (i >= tokensLength) return 0; + + var start = i; + var l = void 0; + + if (l = checkSelector(i)) i += l;else return 0; + + while (i < tokensLength) { + var sb = checkSC(i); + var c = checkDelim(i + sb); + if (!c) break; + var sa = checkSC(i + sb + c); + if (l = checkSelector(i + sb + c + sa)) i += sb + c + sa + l;else break; + } + + tokens[start].selectorsGroupEnd = i; + return i - start; + } + + function getSelectorsGroup() { + var selectorsGroup = []; + var selectorsGroupEnd = tokens[pos].selectorsGroupEnd; + + selectorsGroup.push(getSelector()); + + while (pos < selectorsGroupEnd) { + selectorsGroup = selectorsGroup.concat(getSC()); + selectorsGroup.push(getDelim()); + selectorsGroup = selectorsGroup.concat(getSC()); + selectorsGroup.push(getSelector()); + } + + return selectorsGroup; + } + + function checkSelector(i) { + if (i >= tokensLength) return 0; + + var start = i; + var l = void 0; + + if (l = checkCompoundSelector(i)) i += l;else return 0; + + while (i < tokensLength) { + var sb = checkSC(i); + var c = checkCombinator(i + sb); + if (!sb && !c) break; + var sa = checkSC(i + sb + c); + if (l = checkCompoundSelector(i + sb + c + sa)) i += sb + c + sa + l;else break; + } + + tokens[start].selectorEnd = i; + return i - start; + } + + function getSelector() { + var type = NodeType.SelectorType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var selectorEnd = token.selectorEnd; + var content = void 0; + + content = getCompoundSelector(); + + while (pos < selectorEnd) { + content = content.concat(getSC()); + if (checkCombinator(pos)) content.push(getCombinator()); + content = content.concat(getSC()); + content = content.concat(getCompoundSelector()); + } + + return newNode(type, content, line, column); + } + + function checkCompoundSelector(i) { + var l = void 0; + + if (l = checkCompoundSelector1(i)) { + tokens[i].compoundSelectorType = 1; + } else if (l = checkCompoundSelector2(i)) { + tokens[i].compoundSelectorType = 2; + } + + return l; + } + + function getCompoundSelector() { + var type = tokens[pos].compoundSelectorType; + if (type === 1) return getCompoundSelector1(); + if (type === 2) return getCompoundSelector2(); + } + + function checkCompoundSelector1(i) { + if (i >= tokensLength) return 0; + + var start = i; + + var l = void 0; + if (l = checkUniversalSelector(i) || checkTypeSelector(i)) i += l;else return 0; + + while (i < tokensLength) { + var _l2 = checkShash(i) || checkClass(i) || checkAttributeSelector(i) || checkPseudo(i); + if (_l2) i += _l2;else break; + } + + tokens[start].compoundSelectorEnd = i; + + return i - start; + } + + function getCompoundSelector1() { + var sequence = []; + var compoundSelectorEnd = tokens[pos].compoundSelectorEnd; + + if (checkUniversalSelector(pos)) sequence.push(getUniversalSelector());else sequence.push(getTypeSelector()); + + while (pos < compoundSelectorEnd) { + if (checkShash(pos)) sequence.push(getShash());else if (checkClass(pos)) sequence.push(getClass());else if (checkAttributeSelector(pos)) sequence.push(getAttributeSelector());else if (checkPseudo(pos)) sequence.push(getPseudo()); + } + + return sequence; + } + + function checkCompoundSelector2(i) { + if (i >= tokensLength) return 0; + + var start = i; + + while (i < tokensLength) { + var l = checkShash(i) || checkClass(i) || checkAttributeSelector(i) || checkPseudo(i); + if (l) i += l;else break; + } + + tokens[start].compoundSelectorEnd = i; + + return i - start; + } + + function getCompoundSelector2() { + var sequence = []; + var compoundSelectorEnd = tokens[pos].compoundSelectorEnd; + + while (pos < compoundSelectorEnd) { + if (checkShash(pos)) sequence.push(getShash());else if (checkClass(pos)) sequence.push(getClass());else if (checkAttributeSelector(pos)) sequence.push(getAttributeSelector());else if (checkPseudo(pos)) sequence.push(getPseudo()); + } + + return sequence; + } + + function checkUniversalSelector(i) { + if (i >= tokensLength) return 0; + + var start = i; + var l = void 0; + + if (l = checkNamePrefix(i)) i += l; + + if (tokens[i].type === TokenType.Asterisk) i++;else return 0; + + return i - start; + } + + function getUniversalSelector() { + var type = NodeType.UniversalSelectorType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + var end = void 0; + + if (checkNamePrefix(pos)) { + content.push(getNamePrefix()); + end = getLastPosition(content, line, column, 1); + } + + pos++; + + return newNode(type, content, line, column, end); + } + + function checkTypeSelector(i) { + if (i >= tokensLength) return 0; + + var start = i; + var l = void 0; + + if (l = checkNamePrefix(i)) i += l; + + if (l = checkIdent(i)) i += l;else return 0; + + return i - start; + } + + function getTypeSelector() { + var type = NodeType.TypeSelectorType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + if (checkNamePrefix(pos)) content.push(getNamePrefix()); + + content.push(getIdent()); + + return newNode(type, content, line, column); + } + + function checkAttributeSelector(i) { + var l = void 0; + if (l = checkAttributeSelector1(i)) tokens[i].attributeSelectorType = 1;else if (l = checkAttributeSelector2(i)) tokens[i].attributeSelectorType = 2; + + return l; + } + + function getAttributeSelector() { + var type = tokens[pos].attributeSelectorType; + if (type === 1) return getAttributeSelector1();else return getAttributeSelector2(); + } + + /** * (1) `[panda=nani]` * (2) `[panda='nani']` * (3) `[panda='nani' i]` * - */function checkAttributeSelector1(i){var start=i;if(tokens[i].type === TokenType.LeftSquareBracket)i++;else return 0;var l=undefined;if(l = checkSC(i))i += l;if(l = checkAttributeName(i))i += l;else return 0;if(l = checkSC(i))i += l;if(l = checkAttributeMatch(i))i += l;else return 0;if(l = checkSC(i))i += l;if(l = checkAttributeValue(i))i += l;else return 0;if(l = checkSC(i))i += l;if(l = checkAttributeFlags(i)){i += l;if(l = checkSC(i))i += l;}if(tokens[i].type === TokenType.RightSquareBracket)i++;else return 0;return i - start;}function getAttributeSelector1(){var type=NodeType.AttributeSelectorType;var token=tokens[pos];var line=token.ln;var column=token.col;var content=[]; // Skip `[`. - pos++;content = content.concat(getSC());content.push(getAttributeName());content = content.concat(getSC());content.push(getAttributeMatch());content = content.concat(getSC());content.push(getAttributeValue());content = content.concat(getSC());if(checkAttributeFlags(pos)){content.push(getAttributeFlags());content = content.concat(getSC());} // Skip `]`. - pos++;var end=getLastPosition(content,line,column,1);return newNode(type,content,line,column,end);} /** + */ + function checkAttributeSelector1(i) { + var start = i; + + if (tokens[i].type === TokenType.LeftSquareBracket) i++;else return 0; + + var l = void 0; + if (l = checkSC(i)) i += l; + + if (l = checkAttributeName(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkAttributeMatch(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkAttributeValue(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkAttributeFlags(i)) { + i += l; + if (l = checkSC(i)) i += l; + } + + if (tokens[i].type === TokenType.RightSquareBracket) i++;else return 0; + + return i - start; + } + + function getAttributeSelector1() { + var type = NodeType.AttributeSelectorType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + // Skip `[`. + pos++; + + content = content.concat(getSC()); + content.push(getAttributeName()); + content = content.concat(getSC()); + content.push(getAttributeMatch()); + content = content.concat(getSC()); + content.push(getAttributeValue()); + content = content.concat(getSC()); + + if (checkAttributeFlags(pos)) { + content.push(getAttributeFlags()); + content = content.concat(getSC()); + } + + // Skip `]`. + pos++; + + var end = getLastPosition(content, line, column, 1); + return newNode(type, content, line, column, end); + } + + /** * (1) `[panda]` - */function checkAttributeSelector2(i){var start=i;if(tokens[i].type === TokenType.LeftSquareBracket)i++;else return 0;var l=undefined;if(l = checkSC(i))i += l;if(l = checkAttributeName(i))i += l;else return 0;if(l = checkSC(i))i += l;if(tokens[i].type === TokenType.RightSquareBracket)i++;else return 0;return i - start;}function getAttributeSelector2(){var type=NodeType.AttributeSelectorType;var token=tokens[pos];var line=token.ln;var column=token.col;var content=[]; // Skip `[`. - pos++;content = content.concat(getSC());content.push(getAttributeName());content = content.concat(getSC()); // Skip `]`. - pos++;var end=getLastPosition(content,line,column,1);return newNode(type,content,line,column,end);}function checkAttributeName(i){var start=i;var l=undefined;if(l = checkNamePrefix(i))i += l;if(l = checkIdentOrInterpolation(i))i += l;else return 0;return i - start;}function getAttributeName(){var type=NodeType.AttributeNameType;var token=tokens[pos];var line=token.ln;var column=token.col;var content=[];if(checkNamePrefix(pos))content.push(getNamePrefix());content = content.concat(getIdentOrInterpolation());return newNode(type,content,line,column);}function checkAttributeMatch(i){var l=undefined;if(l = checkAttributeMatch1(i))tokens[i].attributeMatchType = 1;else if(l = checkAttributeMatch2(i))tokens[i].attributeMatchType = 2;return l;}function getAttributeMatch(){var type=tokens[pos].attributeMatchType;if(type === 1)return getAttributeMatch1();else return getAttributeMatch2();}function checkAttributeMatch1(i){var start=i;var type=tokens[i].type;if(type === TokenType.Tilde || type === TokenType.VerticalLine || type === TokenType.CircumflexAccent || type === TokenType.DollarSign || type === TokenType.Asterisk)i++;else return 0;if(tokens[i].type === TokenType.EqualsSign)i++;else return 0;return i - start;}function getAttributeMatch1(){var type=NodeType.AttributeMatchType;var token=tokens[pos];var line=token.ln;var column=token.col;var content=tokens[pos].value + tokens[pos + 1].value;pos += 2;return newNode(type,content,line,column);}function checkAttributeMatch2(i){if(tokens[i].type === TokenType.EqualsSign)return 1;else return 0;}function getAttributeMatch2(){var type=NodeType.AttributeMatchType;var token=tokens[pos];var line=token.ln;var column=token.col;var content='=';pos++;return newNode(type,content,line,column);}function checkAttributeValue(i){return checkString(i) || checkIdentOrInterpolation(i);}function getAttributeValue(){var type=NodeType.AttributeValueType;var token=tokens[pos];var line=token.ln;var column=token.col;var content=[];if(checkString(pos))content.push(getString());else content = content.concat(getIdentOrInterpolation());return newNode(type,content,line,column);}function checkAttributeFlags(i){return checkIdentOrInterpolation(i);}function getAttributeFlags(){var type=NodeType.AttributeFlagsType;var token=tokens[pos];var line=token.ln;var column=token.col;var content=getIdentOrInterpolation();return newNode(type,content,line,column);}function checkNamePrefix(i){if(i >= tokensLength)return 0;var l=undefined;if(l = checkNamePrefix1(i))tokens[i].namePrefixType = 1;else if(l = checkNamePrefix2(i))tokens[i].namePrefixType = 2;return l;}function getNamePrefix(){var type=tokens[pos].namePrefixType;if(type === 1)return getNamePrefix1();else return getNamePrefix2();} /** + */ + function checkAttributeSelector2(i) { + var start = i; + + if (tokens[i].type === TokenType.LeftSquareBracket) i++;else return 0; + + var l = void 0; + if (l = checkSC(i)) i += l; + + if (l = checkAttributeName(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (tokens[i].type === TokenType.RightSquareBracket) i++;else return 0; + + return i - start; + } + + function getAttributeSelector2() { + var type = NodeType.AttributeSelectorType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + // Skip `[`. + pos++; + + content = content.concat(getSC()); + content.push(getAttributeName()); + content = content.concat(getSC()); + + // Skip `]`. + pos++; + + var end = getLastPosition(content, line, column, 1); + return newNode(type, content, line, column, end); + } + + function checkAttributeName(i) { + var start = i; + var l = void 0; + + if (l = checkNamePrefix(i)) i += l; + + if (l = checkIdent(i)) i += l;else return 0; + + return i - start; + } + + function getAttributeName() { + var type = NodeType.AttributeNameType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + if (checkNamePrefix(pos)) content.push(getNamePrefix()); + content.push(getIdent()); + + return newNode(type, content, line, column); + } + + function checkAttributeMatch(i) { + var l = void 0; + if (l = checkAttributeMatch1(i)) tokens[i].attributeMatchType = 1;else if (l = checkAttributeMatch2(i)) tokens[i].attributeMatchType = 2; + + return l; + } + + function getAttributeMatch() { + var type = tokens[pos].attributeMatchType; + if (type === 1) return getAttributeMatch1();else return getAttributeMatch2(); + } + + function checkAttributeMatch1(i) { + var start = i; + + var type = tokens[i].type; + if (type === TokenType.Tilde || type === TokenType.VerticalLine || type === TokenType.CircumflexAccent || type === TokenType.DollarSign || type === TokenType.Asterisk) i++;else return 0; + + if (tokens[i].type === TokenType.EqualsSign) i++;else return 0; + + return i - start; + } + + function getAttributeMatch1() { + var type = NodeType.AttributeMatchType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = tokens[pos].value + tokens[pos + 1].value; + pos += 2; + + return newNode(type, content, line, column); + } + + function checkAttributeMatch2(i) { + if (tokens[i].type === TokenType.EqualsSign) return 1;else return 0; + } + + function getAttributeMatch2() { + var type = NodeType.AttributeMatchType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = '='; + + pos++; + return newNode(type, content, line, column); + } + + function checkAttributeValue(i) { + return checkString(i) || checkIdent(i); + } + + function getAttributeValue() { + var type = NodeType.AttributeValueType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + if (checkString(pos)) content.push(getString());else content.push(getIdent()); + + return newNode(type, content, line, column); + } + + function checkAttributeFlags(i) { + return checkIdent(i); + } + + function getAttributeFlags() { + var type = NodeType.AttributeFlagsType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = [getIdent()]; + + return newNode(type, content, line, column); + } + + function checkNamePrefix(i) { + if (i >= tokensLength) return 0; + + var l = void 0; + if (l = checkNamePrefix1(i)) tokens[i].namePrefixType = 1;else if (l = checkNamePrefix2(i)) tokens[i].namePrefixType = 2; + + return l; + } + + function getNamePrefix() { + var type = tokens[pos].namePrefixType; + if (type === 1) return getNamePrefix1();else return getNamePrefix2(); + } + + /** * (1) `panda|` * (2) `panda<comment>|` - */function checkNamePrefix1(i){var start=i;var l=undefined;if(l = checkNamespacePrefix(i))i += l;else return 0;if(l = checkCommentML(i))i += l;if(l = checkNamespaceSeparator(i))i += l;else return 0;return i - start;}function getNamePrefix1(){var type=NodeType.NamePrefixType;var token=tokens[pos];var line=token.ln;var column=token.col;var content=[];content.push(getNamespacePrefix());if(checkCommentML(pos))content.push(getCommentML());content.push(getNamespaceSeparator());return newNode(type,content,line,column);} /** + */ + function checkNamePrefix1(i) { + var start = i; + var l = void 0; + + if (l = checkNamespacePrefix(i)) i += l;else return 0; + + if (l = checkCommentML(i)) i += l; + + if (l = checkNamespaceSeparator(i)) i += l;else return 0; + + return i - start; + } + + function getNamePrefix1() { + var type = NodeType.NamePrefixType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + content.push(getNamespacePrefix()); + + if (checkCommentML(pos)) content.push(getCommentML()); + + content.push(getNamespaceSeparator()); + + return newNode(type, content, line, column); + } + + /** * (1) `|` - */function checkNamePrefix2(i){return checkNamespaceSeparator(i);}function getNamePrefix2(){var type=NodeType.NamePrefixType;var token=tokens[pos];var line=token.ln;var column=token.col;var content=[getNamespaceSeparator()];return newNode(type,content,line,column);} /** + */ + function checkNamePrefix2(i) { + return checkNamespaceSeparator(i); + } + + function getNamePrefix2() { + var type = NodeType.NamePrefixType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = [getNamespaceSeparator()]; + + return newNode(type, content, line, column); + } + + /** * (1) `*` * (2) `panda` - */function checkNamespacePrefix(i){if(i >= tokensLength)return 0;var l=undefined;if(tokens[i].type === TokenType.Asterisk)return 1;else if(l = checkIdentOrInterpolation(i))return l;else return 0;}function getNamespacePrefix(){var type=NodeType.NamespacePrefixType;var token=tokens[pos];var line=token.ln;var column=token.col;var content=[];if(checkIdentOrInterpolation(pos))content = content.concat(getIdentOrInterpolation());return newNode(type,content,line,column);} /** + */ + function checkNamespacePrefix(i) { + if (i >= tokensLength) return 0; + + var l = void 0; + + if (tokens[i].type === TokenType.Asterisk) return 1;else if (l = checkIdent(i)) return l;else return 0; + } + + function getNamespacePrefix() { + var type = NodeType.NamespacePrefixType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + if (tokens[pos].type === TokenType.Asterisk) { + var asteriskNode = newNode(NodeType.IdentType, '*', line, column); + content.push(asteriskNode); + pos++; + } else if (checkIdent(pos)) content.push(getIdent()); + + return newNode(type, content, line, column); + } + + /** * (1) `|` - */function checkNamespaceSeparator(i){if(i >= tokensLength)return 0;if(tokens[i].type === TokenType.VerticalLine)return 1;else return 0;}function getNamespaceSeparator(){var type=NodeType.NamespaceSeparatorType;var token=tokens[pos];var line=token.ln;var column=token.col;var content='|';pos++;return newNode(type,content,line,column);} + */ + function checkNamespaceSeparator(i) { + if (i >= tokensLength) return 0; + + if (tokens[i].type !== TokenType.VerticalLine) return 0; + + // Return false if `|=` - [attr|=value] + if (tokens[i + 1] && tokens[i + 1].type === TokenType.EqualsSign) return 0; + + return 1; + } + + function getNamespaceSeparator() { + var type = NodeType.NamespaceSeparatorType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = '|'; + + pos++; + return newNode(type, content, line, column); + } + + module.exports = function (_tokens, context) { + tokens = _tokens; + tokensLength = tokens.length; + pos = 0; + + return contexts[context](); + }; /***/ }, -/* 14 */ +/* 15 */ /***/ function(module, exports) { 'use strict'; @@ -1834,7 +4624,10 @@ StringType: 'string', StylesheetType: 'stylesheet', TypeSelectorType: 'typeSelector', + UnicodeRangeType: 'unicodeRange', + UniversalSelectorType: 'universalSelector', UriType: 'uri', + UrangeType: 'urange', ValueType: 'value', VariableType: 'variable', VariablesListType: 'variablesList', @@ -1842,19 +4635,5282 @@ }; /***/ }, -/* 15 */ +/* 16 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; module.exports = function (css, tabSize) { - var TokenType = __webpack_require__(12); + var TokenType = __webpack_require__(13); var tokens = []; var urlMode = false; var blockMode = 0; - var c = undefined; // Current character - var cn = undefined; // Next character + var pos = 0; + var tn = 0; + var ln = 1; + var col = 1; + var cssLength = 0; + + var Punctuation = { + ' ': TokenType.Space, + '\n': TokenType.Newline, + '\r': TokenType.Newline, + '\t': TokenType.Tab, + '!': TokenType.ExclamationMark, + '"': TokenType.QuotationMark, + '#': TokenType.NumberSign, + '$': TokenType.DollarSign, + '%': TokenType.PercentSign, + '&': TokenType.Ampersand, + '\'': TokenType.Apostrophe, + '(': TokenType.LeftParenthesis, + ')': TokenType.RightParenthesis, + '*': TokenType.Asterisk, + '+': TokenType.PlusSign, + ',': TokenType.Comma, + '-': TokenType.HyphenMinus, + '.': TokenType.FullStop, + '/': TokenType.Solidus, + ':': TokenType.Colon, + ';': TokenType.Semicolon, + '<': TokenType.LessThanSign, + '=': TokenType.EqualsSign, + '>': TokenType.GreaterThanSign, + '?': TokenType.QuestionMark, + '@': TokenType.CommercialAt, + '[': TokenType.LeftSquareBracket, + ']': TokenType.RightSquareBracket, + '^': TokenType.CircumflexAccent, + '_': TokenType.LowLine, + '{': TokenType.LeftCurlyBracket, + '|': TokenType.VerticalLine, + '}': TokenType.RightCurlyBracket, + '~': TokenType.Tilde + }; + + /** + * Add a token to the token list + * @param {string} type + * @param {string} value + */ + function pushToken(type, value, column) { + tokens.push({ + tn: tn++, + ln: ln, + col: column, + type: type, + value: value + }); + } + + /** + * Check if a character is a decimal digit + * @param {string} c Character + * @returns {boolean} + */ + function isDecimalDigit(c) { + return '0123456789'.indexOf(c) >= 0; + } + + /** + * Parse spaces + * @param {string} css Unparsed part of CSS string + */ + function parseSpaces(css) { + var start = pos; + + // Read the string until we meet a non-space character: + for (; pos < cssLength; pos++) { + if (css.charAt(pos) !== ' ') break; + } + + // Add a substring containing only spaces to tokens: + pushToken(TokenType.Space, css.substring(start, pos--), col); + col += pos - start; + } + + /** + * Parse a string within quotes + * @param {string} css Unparsed part of CSS string + * @param {string} q Quote (either `'` or `"`) + */ + function parseString(css, q) { + var start = pos; + + // Read the string until we meet a matching quote: + for (pos++; pos < cssLength; pos++) { + // Skip escaped quotes: + if (css.charAt(pos) === '\\') pos++;else if (css.charAt(pos) === q) break; + } + + // Add the string (including quotes) to tokens: + pushToken(q === '"' ? TokenType.StringDQ : TokenType.StringSQ, css.substring(start, pos + 1), col); + col += pos - start; + } + + /** + * Parse numbers + * @param {string} css Unparsed part of CSS string + */ + function parseDecimalNumber(css) { + var start = pos; + + // Read the string until we meet a character that's not a digit: + for (; pos < cssLength; pos++) { + if (!isDecimalDigit(css.charAt(pos))) break; + } + + // Add the number to tokens: + pushToken(TokenType.DecimalNumber, css.substring(start, pos--), col); + col += pos - start; + } + + /** + * Parse identifier + * @param {string} css Unparsed part of CSS string + */ + function parseIdentifier(css) { + var start = pos; + + // Skip all opening slashes: + while (css.charAt(pos) === '/') { + pos++; + } // Read the string until we meet a punctuation mark: + for (; pos < cssLength; pos++) { + // Skip all '\': + if (css.charAt(pos) === '\\') pos++;else if (Punctuation[css.charAt(pos)]) break; + } + + var ident = css.substring(start, pos--); + + // Enter url mode if parsed substring is `url`: + urlMode = urlMode || ident === 'url'; + + // Add identifier to tokens: + pushToken(TokenType.Identifier, ident, col); + col += pos - start; + } + + /** + * Parse a multiline comment + * @param {string} css Unparsed part of CSS string + */ + function parseMLComment(css) { + var start = pos; + + // Read the string until we meet `*/`. + // Since we already know first 2 characters (`/*`), start reading + // from `pos + 2`: + for (pos = pos + 2; pos < cssLength; pos++) { + if (css.charAt(pos) === '*' && css.charAt(pos + 1) === '/') { + pos++; + break; + } + } + + // Add full comment (including `/*` and `*/`) to the list of tokens: + var comment = css.substring(start, pos + 1); + pushToken(TokenType.CommentML, comment, col); + + var newlines = comment.split('\n'); + if (newlines.length > 1) { + ln += newlines.length - 1; + col = newlines[newlines.length - 1].length; + } else { + col += pos - start; + } + } + + function parseSLComment(css) { + var start = pos; + + // Read the string until we meet line break. + // Since we already know first 2 characters (`//`), start reading + // from `pos + 2`: + for (pos += 2; pos < cssLength; pos++) { + if (css.charAt(pos) === '\n' || css.charAt(pos) === '\r') { + break; + } + } + + // Add comment (including `//` and line break) to the list of tokens: + pushToken(TokenType.CommentSL, css.substring(start, pos--), col); + col += pos - start; + } + + /** + * Convert a CSS string to a list of tokens + * @param {string} css CSS string + * @returns {Array} List of tokens + * @private + */ + function getTokens(css) { + var c; // Current character + var cn; // Next character + + cssLength = css.length; + + // Parse string, character by character: + for (pos = 0; pos < cssLength; col++, pos++) { + c = css.charAt(pos); + cn = css.charAt(pos + 1); + + // If we meet `/*`, it's a start of a multiline comment. + // Parse following characters as a multiline comment: + if (c === '/' && cn === '*') { + parseMLComment(css); + } + + // If we meet `//` and it is not a part of url: + else if (!urlMode && c === '/' && cn === '/') { + // If we're currently inside a block, treat `//` as a start + // of identifier. Else treat `//` as a start of a single-line + // comment: + if (blockMode > 0) parseIdentifier(css);else parseSLComment(css); + } + + // If current character is a double or single quote, it's a start + // of a string: + else if (c === '"' || c === "'") { + parseString(css, c); + } + + // If current character is a space: + else if (c === ' ') { + parseSpaces(css); + } + + // If current character is a punctuation mark: + else if (Punctuation[c]) { + // Add it to the list of tokens: + pushToken(Punctuation[c], c, col); + if (c === '\n' || c === '\r') { + ln++; + col = 0; + } // Go to next line + else if (c === ')') urlMode = false; // Exit url mode + else if (c === '{') blockMode++; // Enter a block + else if (c === '}') blockMode--; // Exit a block + else if (c === '\t' && tabSize > 1) col += tabSize - 1; + } + + // If current character is a decimal digit: + else if (isDecimalDigit(c)) { + parseDecimalNumber(css); + } + + // If current character is anything else: + else { + parseIdentifier(css); + } + } + + return tokens; + } + + return getTokens(css); + }; + +/***/ }, +/* 17 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + exports.default = { + mark: __webpack_require__(18), + parse: __webpack_require__(19), + stringify: __webpack_require__(6), + tokenizer: __webpack_require__(20) + }; + module.exports = exports['default']; + +/***/ }, +/* 18 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var TokenType = __webpack_require__(13); + + module.exports = function () { + /** + * Mark whitespaces and comments + */ + function markSC(tokens) { + var tokensLength = tokens.length; + var ws = -1; // Flag for whitespaces + var sc = -1; // Flag for whitespaces and comments + var t = void 0; // Current token + + // For every token in the token list, mark spaces and line breaks + // as spaces (set both `ws` and `sc` flags). Mark multiline comments + // with `sc` flag. + // If there are several spaces or tabs or line breaks or multiline + // comments in a row, group them: take the last one's index number + // and save it to the first token in the group as a reference: + // e.g., `ws_last = 7` for a group of whitespaces or `sc_last = 9` + // for a group of whitespaces and comments. + for (var i = 0; i < tokensLength; i++) { + t = tokens[i]; + switch (t.type) { + case TokenType.Space: + case TokenType.Tab: + case TokenType.Newline: + t.ws = true; + t.sc = true; + + if (ws === -1) ws = i; + if (sc === -1) sc = i; + + break; + case TokenType.CommentML: + case TokenType.CommentSL: + if (ws !== -1) { + tokens[ws].ws_last = i - 1; + ws = -1; + } + + t.sc = true; + + break; + default: + if (ws !== -1) { + tokens[ws].ws_last = i - 1; + ws = -1; + } + + if (sc !== -1) { + tokens[sc].sc_last = i - 1; + sc = -1; + } + } + } + + if (ws !== -1) tokens[ws].ws_last = i - 1; + if (sc !== -1) tokens[sc].sc_last = i - 1; + } + + /** + * Pair brackets + */ + function markBrackets(tokens) { + var tokensLength = tokens.length; + var ps = []; // Parentheses + var sbs = []; // Square brackets + var cbs = []; // Curly brackets + var t = void 0; // Current token + + // For every token in the token list, if we meet an opening (left) + // bracket, push its index number to a corresponding array. + // If we then meet a closing (right) bracket, look at the corresponding + // array. If there are any elements (records about previously met + // left brackets), take a token of the last left bracket (take + // the last index number from the array and find a token with + // this index number) and save right bracket's index as a reference: + for (var i = 0; i < tokensLength; i++) { + t = tokens[i]; + switch (t.type) { + case TokenType.LeftParenthesis: + ps.push(i); + break; + case TokenType.RightParenthesis: + if (ps.length) { + t.left = ps.pop(); + tokens[t.left].right = i; + } + break; + case TokenType.LeftSquareBracket: + sbs.push(i); + break; + case TokenType.RightSquareBracket: + if (sbs.length) { + t.left = sbs.pop(); + tokens[t.left].right = i; + } + break; + case TokenType.LeftCurlyBracket: + cbs.push(i); + break; + case TokenType.RightCurlyBracket: + if (cbs.length) { + t.left = cbs.pop(); + tokens[t.left].right = i; + } + break; + } + } + } + + return function (tokens) { + markBrackets(tokens); + markSC(tokens); + }; + }(); + +/***/ }, +/* 19 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var Node = __webpack_require__(1); + var NodeType = __webpack_require__(15); + var TokenType = __webpack_require__(13); + + var tokens = void 0; + var tokensLength = void 0; + var pos = void 0; + + var contexts = { + 'arguments': function _arguments() { + return checkArguments(pos) && getArguments(); + }, + 'atkeyword': function atkeyword() { + return checkAtkeyword(pos) && getAtkeyword(); + }, + 'atrule': function atrule() { + return checkAtrule(pos) && getAtrule(); + }, + 'block': function block() { + return checkBlock(pos) && getBlock(); + }, + 'brackets': function brackets() { + return checkBrackets(pos) && getBrackets(); + }, + 'class': function _class() { + return checkClass(pos) && getClass(); + }, + 'combinator': function combinator() { + return checkCombinator(pos) && getCombinator(); + }, + 'commentML': function commentML() { + return checkCommentML(pos) && getCommentML(); + }, + 'commentSL': function commentSL() { + return checkCommentSL(pos) && getCommentSL(); + }, + 'condition': function condition() { + return checkCondition(pos) && getCondition(); + }, + 'conditionalStatement': function conditionalStatement() { + return checkConditionalStatement(pos) && getConditionalStatement(); + }, + 'declaration': function declaration() { + return checkDeclaration(pos) && getDeclaration(); + }, + 'declDelim': function declDelim() { + return checkDeclDelim(pos) && getDeclDelim(); + }, + 'default': function _default() { + return checkDefault(pos) && getDefault(); + }, + 'delim': function delim() { + return checkDelim(pos) && getDelim(); + }, + 'dimension': function dimension() { + return checkDimension(pos) && getDimension(); + }, + 'expression': function expression() { + return checkExpression(pos) && getExpression(); + }, + 'extend': function extend() { + return checkExtend(pos) && getExtend(); + }, + 'function': function _function() { + return checkFunction(pos) && getFunction(); + }, + 'global': function global() { + return checkGlobal(pos) && getGlobal(); + }, + 'ident': function ident() { + return checkIdent(pos) && getIdent(); + }, + 'important': function important() { + return checkImportant(pos) && getImportant(); + }, + 'include': function include() { + return checkInclude(pos) && getInclude(); + }, + 'interpolation': function interpolation() { + return checkInterpolation(pos) && getInterpolation(); + }, + 'loop': function loop() { + return checkLoop(pos) && getLoop(); + }, + 'mixin': function mixin() { + return checkMixin(pos) && getMixin(); + }, + 'namespace': function namespace() { + return checkNamespace(pos) && getNamespace(); + }, + 'number': function number() { + return checkNumber(pos) && getNumber(); + }, + 'operator': function operator() { + return checkOperator(pos) && getOperator(); + }, + 'optional': function optional() { + return checkOptional(pos) && getOptional(); + }, + 'parentheses': function parentheses() { + return checkParentheses(pos) && getParentheses(); + }, + 'parentselector': function parentselector() { + return checkParentSelector(pos) && getParentSelector(); + }, + 'percentage': function percentage() { + return checkPercentage(pos) && getPercentage(); + }, + 'placeholder': function placeholder() { + return checkPlaceholder(pos) && getPlaceholder(); + }, + 'progid': function progid() { + return checkProgid(pos) && getProgid(); + }, + 'property': function property() { + return checkProperty(pos) && getProperty(); + }, + 'propertyDelim': function propertyDelim() { + return checkPropertyDelim(pos) && getPropertyDelim(); + }, + 'pseudoc': function pseudoc() { + return checkPseudoc(pos) && getPseudoc(); + }, + 'pseudoe': function pseudoe() { + return checkPseudoe(pos) && getPseudoe(); + }, + 'ruleset': function ruleset() { + return checkRuleset(pos) && getRuleset(); + }, + 's': function s() { + return checkS(pos) && getS(); + }, + 'selector': function selector() { + return checkSelector(pos) && getSelector(); + }, + 'shash': function shash() { + return checkShash(pos) && getShash(); + }, + 'string': function string() { + return checkString(pos) && getString(); + }, + 'stylesheet': function stylesheet() { + return checkStylesheet(pos) && getStylesheet(); + }, + 'typeSelector': function typeSelector() { + return checkTypeSelector(pos) && getTypeSelector(); + }, + 'unary': function unary() { + return checkUnary(pos) && getUnary(); + }, + 'unicodeRange': function unicodeRange() { + return checkUnicodeRange(pos) && getUnicodeRange(); + }, + 'universalSelector': function universalSelector() { + return checkUniversalSelector(pos) && getUniversalSelector(); + }, + 'urange': function urange() { + return checkUrange(pos) && getUrange(); + }, + 'uri': function uri() { + return checkUri(pos) && getUri(); + }, + 'value': function value() { + return checkValue(pos) && getValue(); + }, + 'variable': function variable() { + return checkVariable(pos) && getVariable(); + }, + 'variableslist': function variableslist() { + return checkVariablesList(pos) && getVariablesList(); + }, + 'vhash': function vhash() { + return checkVhash(pos) && getVhash(); + } + }; + + /** + * Stop parsing and display error + * @param {Number=} i Token's index number + */ + function throwError(i) { + var ln = i ? tokens[i].ln : tokens[pos].ln; + + throw { line: ln, syntax: 'scss' }; + } + + /** + * @param {Number} start + * @param {Number} finish + * @returns {String} + */ + function joinValues(start, finish) { + var s = ''; + + for (var i = start; i < finish + 1; i++) { + s += tokens[i].value; + } + + return s; + } + + /** + * @param {Number} start + * @param {Number} num + * @returns {String} + */ + function joinValues2(start, num) { + if (start + num - 1 >= tokensLength) return; + + var s = ''; + + for (var i = 0; i < num; i++) { + s += tokens[start + i].value; + } + + return s; + } + + function getLastPosition(content, line, column, colOffset) { + return typeof content === 'string' ? getLastPositionForString(content, line, column, colOffset) : getLastPositionForArray(content, line, column, colOffset); + } + + function getLastPositionForString(content, line, column, colOffset) { + var position = []; + + if (!content) { + position = [line, column]; + if (colOffset) position[1] += colOffset - 1; + return position; + } + + var lastLinebreak = content.lastIndexOf('\n'); + var endsWithLinebreak = lastLinebreak === content.length - 1; + var splitContent = content.split('\n'); + var linebreaksCount = splitContent.length - 1; + var prevLinebreak = linebreaksCount === 0 || linebreaksCount === 1 ? -1 : content.length - splitContent[linebreaksCount - 1].length - 2; + + // Line: + var offset = endsWithLinebreak ? linebreaksCount - 1 : linebreaksCount; + position[0] = line + offset; + + // Column: + if (endsWithLinebreak) { + offset = prevLinebreak !== -1 ? content.length - prevLinebreak : content.length - 1; + } else { + offset = linebreaksCount !== 0 ? content.length - lastLinebreak - column - 1 : content.length - 1; + } + position[1] = column + offset; + + if (!colOffset) return position; + + if (endsWithLinebreak) { + position[0]++; + position[1] = colOffset; + } else { + position[1] += colOffset; + } + + return position; + } + + function getLastPositionForArray(content, line, column, colOffset) { + var position; + + if (content.length === 0) { + position = [line, column]; + } else { + var c = content[content.length - 1]; + if (c.hasOwnProperty('end')) { + position = [c.end.line, c.end.column]; + } else { + position = getLastPosition(c.content, line, column); + } + } + + if (!colOffset) return position; + + if (tokens[pos - 1] && tokens[pos - 1].type !== 'Newline') { + position[1] += colOffset; + } else { + position[0]++; + position[1] = 1; + } + + return position; + } + + function newNode(type, content, line, column, end) { + if (!end) end = getLastPosition(content, line, column); + return new Node({ + type: type, + content: content, + start: { + line: line, + column: column + }, + end: { + line: end[0], + column: end[1] + }, + syntax: 'scss' + }); + } + + /** + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkAny(i) { + var l = void 0; + + if (l = checkBrackets(i)) tokens[i].any_type = 1;else if (l = checkParentheses(i)) tokens[i].any_type = 2;else if (l = checkString(i)) tokens[i].any_type = 3;else if (l = checkVariablesList(i)) tokens[i].any_type = 4;else if (l = checkVariable(i)) tokens[i].any_type = 5;else if (l = checkPlaceholder(i)) tokens[i].any_type = 6;else if (l = checkPercentage(i)) tokens[i].any_type = 7;else if (l = checkDimension(i)) tokens[i].any_type = 8;else if (l = checkUnicodeRange(i)) tokens[i].any_type = 9;else if (l = checkNumber(i)) tokens[i].any_type = 10;else if (l = checkUri(i)) tokens[i].any_type = 11;else if (l = checkExpression(i)) tokens[i].any_type = 12;else if (l = checkFunction(i)) tokens[i].any_type = 13;else if (l = checkInterpolation(i)) tokens[i].any_type = 14;else if (l = checkIdent(i)) tokens[i].any_type = 15;else if (l = checkClass(i)) tokens[i].any_type = 16;else if (l = checkUnary(i)) tokens[i].any_type = 17; + + return l; + } + + /** + * @returns {Array} + */ + function getAny() { + var type = tokens[pos].any_type; + + if (type === 1) return getBrackets(); + if (type === 2) return getParentheses(); + if (type === 3) return getString(); + if (type === 4) return getVariablesList(); + if (type === 5) return getVariable(); + if (type === 6) return getPlaceholder(); + if (type === 7) return getPercentage(); + if (type === 8) return getDimension(); + if (type === 9) return getUnicodeRange(); + if (type === 10) return getNumber(); + if (type === 11) return getUri(); + if (type === 12) return getExpression(); + if (type === 13) return getFunction(); + if (type === 14) return getInterpolation(); + if (type === 15) return getIdent(); + if (type === 16) return getClass(); + if (type === 17) return getUnary(); + } + + /** + * Check if token is part of mixin's arguments. + * @param {Number} i Token's index number + * @returns {Number} Length of arguments + */ + function checkArguments(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis) return 0; + + i++; + + while (i < tokens[start].right) { + if (l = checkArgument(i)) i += l;else return 0; + } + + return tokens[start].right - start + 1; + } + + /** + * Check if token is valid to be part of arguments list + * @param {Number} i Token's index number + * @returns {Number} Length of argument + */ + function checkArgument(i) { + return checkBrackets(i) || checkParentheses(i) || checkSingleValueDeclaration(i) || checkFunction(i) || checkVariablesList(i) || checkVariable(i) || checkSC(i) || checkDelim(i) || checkDeclDelim(i) || checkString(i) || checkPercentage(i) || checkDimension(i) || checkNumber(i) || checkUri(i) || checkInterpolation(i) || checkIdent(i) || checkVhash(i) || checkOperator(i) || checkUnary(i) || checkImportant(i) || checkGlobal(i) || checkDefault(i) || checkOptional(i) || checkParentSelector(i); + } + + /** + * @returns {Array} Node that is part of arguments list + */ + function getArgument() { + if (checkBrackets(pos)) return getBrackets();else if (checkParentheses(pos)) return getParentheses();else if (checkSingleValueDeclaration(pos)) return getSingleValueDeclaration();else if (checkFunction(pos)) return getFunction();else if (checkVariablesList(pos)) return getVariablesList();else if (checkVariable(pos)) return getVariable();else if (checkSC(pos)) return getSC();else if (checkDelim(pos)) return getDelim();else if (checkDeclDelim(pos)) return getDeclDelim();else if (checkString(pos)) return getString();else if (checkPercentage(pos)) return getPercentage();else if (checkDimension(pos)) return getDimension();else if (checkNumber(pos)) return getNumber();else if (checkUri(pos)) return getUri();else if (checkInterpolation(pos)) return getInterpolation();else if (checkIdent(pos)) return getIdent();else if (checkVhash(pos)) return getVhash();else if (checkOperator(pos)) return getOperator();else if (checkUnary(pos)) return getUnary();else if (checkImportant(pos)) return getImportant();else if (checkGlobal(pos)) return getGlobal();else if (checkDefault(pos)) return getDefault();else if (checkOptional(pos)) return getOptional();else if (checkParentSelector(pos)) return getParentSelector(); + } + + /** + * Check if token is part of an @-word (e.g. `@import`, `@include`) + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkAtkeyword(i) { + var l; + + // Check that token is `@`: + if (i >= tokensLength || tokens[i++].type !== TokenType.CommercialAt) return 0; + + return (l = checkIdentOrInterpolation(i)) ? l + 1 : 0; + } + + /** + * Get node with @-word + * @returns {Array} `['atkeyword', ['ident', x]]` where `x` is + * an identifier without + * `@` (e.g. `import`, `include`) + */ + function getAtkeyword() { + var startPos = pos; + var x = void 0; + + pos++; + + x = getIdentOrInterpolation(); + + var token = tokens[startPos]; + return newNode(NodeType.AtkeywordType, x, token.ln, token.col); + } + + /** + * Check if token is a part of an @-rule + * @param {Number} i Token's index number + * @returns {Number} Length of @-rule + */ + function checkAtrule(i) { + var l; + + if (i >= tokensLength) return 0; + + // If token already has a record of being part of an @-rule, + // return the @-rule's length: + if (tokens[i].atrule_l !== undefined) return tokens[i].atrule_l; + + // If token is part of an @-rule, save the rule's type to token. + // @keyframes: + if (l = checkKeyframesRule(i)) tokens[i].atrule_type = 4; + // @-rule with ruleset: + else if (l = checkAtruler(i)) tokens[i].atrule_type = 1; + // Block @-rule: + else if (l = checkAtruleb(i)) tokens[i].atrule_type = 2; + // Single-line @-rule: + else if (l = checkAtrules(i)) tokens[i].atrule_type = 3;else return 0; + + // If token is part of an @-rule, save the rule's length to token: + tokens[i].atrule_l = l; + + return l; + } + + /** + * Get node with @-rule + * @returns {Array} + */ + function getAtrule() { + switch (tokens[pos].atrule_type) { + case 1: + return getAtruler(); // @-rule with ruleset + case 2: + return getAtruleb(); // Block @-rule + case 3: + return getAtrules(); // Single-line @-rule + case 4: + return getKeyframesRule(); + } + } + + /** + * Check if token is part of a block @-rule + * @param {Number} i Token's index number + * @returns {Number} Length of the @-rule + */ + function checkAtruleb(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkAtkeyword(i)) i += l;else return 0; + + if (l = checkTsets(i)) i += l; + + if (l = checkBlock(i)) i += l;else return 0; + + return i - start; + } + + /** + * Get node with a block @-rule + * @returns {Array} `['atruleb', ['atkeyword', x], y, ['block', z]]` + */ + function getAtruleb() { + var startPos = pos; + var x = void 0; + + x = [getAtkeyword()].concat(getTsets()).concat([getBlock()]); + + var token = tokens[startPos]; + return newNode(NodeType.AtruleType, x, token.ln, token.col); + } + + /** + * Check if token is part of an @-rule with ruleset + * @param {Number} i Token's index number + * @returns {Number} Length of the @-rule + */ + function checkAtruler(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkAtkeyword(i)) i += l;else return 0; + + if (l = checkTsets(i)) i += l; + + if (i < tokensLength && tokens[i].type === TokenType.LeftCurlyBracket) i++;else return 0; + + if (l = checkAtrulers(i)) i += l; + + if (i < tokensLength && tokens[i].type === TokenType.RightCurlyBracket) i++;else return 0; + + return i - start; + } + + /** + * Get node with an @-rule with ruleset + * @returns {Array} ['atruler', ['atkeyword', x], y, z] + */ + function getAtruler() { + var startPos = pos; + var x = void 0; + + x = [getAtkeyword()].concat(getTsets()); + + x.push(getAtrulers()); + + var token = tokens[startPos]; + return newNode(NodeType.AtruleType, x, token.ln, token.col); + } + + /** + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkAtrulers(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + while (l = checkRuleset(i) || checkAtrule(i) || checkSC(i)) { + i += l; + } + + if (i < tokensLength) tokens[i].atrulers_end = 1; + + return i - start; + } + + /** + * @returns {Array} `['atrulers', x]` + */ + function getAtrulers() { + var startPos = pos; + var x = void 0; + var token = tokens[startPos]; + var line = token.ln; + var column = token.col; + pos++; + + x = getSC(); + + while (!tokens[pos].atrulers_end) { + if (checkSC(pos)) x = x.concat(getSC());else if (checkAtrule(pos)) x.push(getAtrule());else if (checkRuleset(pos)) x.push(getRuleset()); + } + + x = x.concat(getSC()); + + var end = getLastPosition(x, line, column, 1); + pos++; + + return newNode(NodeType.BlockType, x, token.ln, token.col, end); + } + + /** + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkAtrules(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkAtkeyword(i)) i += l;else return 0; + + if (l = checkTsets(i)) i += l; + + return i - start; + } + + /** + * @returns {Array} `['atrules', ['atkeyword', x], y]` + */ + function getAtrules() { + var startPos = pos; + var x = void 0; + + x = [getAtkeyword()].concat(getTsets()); + + var token = tokens[startPos]; + return newNode(NodeType.AtruleType, x, token.ln, token.col); + } + + /** + * Check if token is part of a block (e.g. `{...}`). + * @param {Number} i Token's index number + * @returns {Number} Length of the block + */ + function checkBlock(i) { + return i < tokensLength && tokens[i].type === TokenType.LeftCurlyBracket ? tokens[i].right - i + 1 : 0; + } + + /** + * Get node with a block + * @returns {Array} `['block', x]` + */ + function getBlock() { + var startPos = pos; + var end = tokens[pos].right; + var x = []; + var token = tokens[startPos]; + var line = token.ln; + var column = token.col; + + pos++; + + while (pos < end) { + if (checkBlockdecl(pos)) x = x.concat(getBlockdecl());else throwError(); + } + + var end_ = getLastPosition(x, line, column, 1); + pos = end + 1; + + return newNode(NodeType.BlockType, x, token.ln, token.col, end_); + } + + /** + * Check if token is part of a declaration (property-value pair) + * @param {Number} i Token's index number + * @returns {Number} Length of the declaration + */ + function checkBlockdecl(i) { + var l; + + if (i >= tokensLength) return 0; + + if (l = checkBlockdecl1(i)) tokens[i].bd_type = 1;else if (l = checkBlockdecl2(i)) tokens[i].bd_type = 2;else if (l = checkBlockdecl3(i)) tokens[i].bd_type = 3;else if (l = checkBlockdecl4(i)) tokens[i].bd_type = 4;else return 0; + + return l; + } + + /** + * @returns {Array} + */ + function getBlockdecl() { + switch (tokens[pos].bd_type) { + case 1: + return getBlockdecl1(); + case 2: + return getBlockdecl2(); + case 3: + return getBlockdecl3(); + case 4: + return getBlockdecl4(); + } + } + + /** + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkBlockdecl1(i) { + var start = i; + var l = void 0; + + if (l = checkSC(i)) i += l; + + if (l = checkConditionalStatement(i)) tokens[i].bd_kind = 1;else if (l = checkInclude(i)) tokens[i].bd_kind = 2;else if (l = checkExtend(i)) tokens[i].bd_kind = 4;else if (l = checkLoop(i)) tokens[i].bd_kind = 3;else if (l = checkAtrule(i)) tokens[i].bd_kind = 6;else if (l = checkRuleset(i)) tokens[i].bd_kind = 7;else if (l = checkDeclaration(i)) tokens[i].bd_kind = 5;else return 0; + + i += l; + + if (i < tokensLength && (l = checkDeclDelim(i))) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + return i - start; + } + + /** + * @returns {Array} + */ + function getBlockdecl1() { + var sc = getSC(); + var x = void 0; + + switch (tokens[pos].bd_kind) { + case 1: + x = getConditionalStatement(); + break; + case 2: + x = getInclude(); + break; + case 3: + x = getLoop(); + break; + case 4: + x = getExtend(); + break; + case 5: + x = getDeclaration(); + break; + case 6: + x = getAtrule(); + break; + case 7: + x = getRuleset(); + break; + } + + return sc.concat([x]).concat([getDeclDelim()]).concat(getSC()); + } + + /** + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkBlockdecl2(i) { + var start = i; + var l = void 0; + + if (l = checkSC(i)) i += l; + + if (l = checkConditionalStatement(i)) tokens[i].bd_kind = 1;else if (l = checkInclude(i)) tokens[i].bd_kind = 2;else if (l = checkExtend(i)) tokens[i].bd_kind = 4;else if (l = checkMixin(i)) tokens[i].bd_kind = 8;else if (l = checkLoop(i)) tokens[i].bd_kind = 3;else if (l = checkAtrule(i)) tokens[i].bd_kind = 6;else if (l = checkRuleset(i)) tokens[i].bd_kind = 7;else if (l = checkDeclaration(i)) tokens[i].bd_kind = 5;else return 0; + + i += l; + + if (l = checkSC(i)) i += l; + + return i - start; + } + + /** + * @returns {Array} + */ + function getBlockdecl2() { + var sc = getSC(); + var x = void 0; + + switch (tokens[pos].bd_kind) { + case 1: + x = getConditionalStatement(); + break; + case 2: + x = getInclude(); + break; + case 3: + x = getLoop(); + break; + case 4: + x = getExtend(); + break; + case 5: + x = getDeclaration(); + break; + case 6: + x = getAtrule(); + break; + case 7: + x = getRuleset(); + break; + case 8: + x = getMixin(); + break; + } + + return sc.concat([x]).concat(getSC()); + } + + /** + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkBlockdecl3(i) { + var start = i; + var l = void 0; + + if (l = checkSC(i)) i += l; + + if (l = checkDeclDelim(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + return i - start; + } + + /** + * @returns {Array} `[s0, ['declDelim'], s1]` where `s0` and `s1` are + * are optional whitespaces. + */ + function getBlockdecl3() { + return getSC().concat([getDeclDelim()]).concat(getSC()); + } + + /** + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkBlockdecl4(i) { + return checkSC(i); + } + + /** + * @returns {Array} + */ + function getBlockdecl4() { + return getSC(); + } + + /** + * Check if token is part of text inside square brackets, e.g. `[1]` + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkBrackets(i) { + if (i >= tokensLength) return 0; + + var start = i; + + if (tokens[i].type === TokenType.LeftSquareBracket) i++;else return 0; + + if (i < tokens[start].right) { + var l = checkTsets(i); + if (l) i += l;else return 0; + } + + i++; + + return i - start; + } + + /** + * Get node with text inside parentheses or square brackets (e.g. `(1)`) + * @return {Node} + */ + function getBrackets() { + var startPos = pos; + var token = tokens[startPos]; + var line = token.ln; + var column = token.col; + var tsets = []; + var right = token.right; + + pos++; + + if (pos < right) { + tsets = getTsets(); + } + + var end = getLastPosition(tsets, line, column, 1); + pos++; + + return newNode(NodeType.BracketsType, tsets, token.ln, token.col, end); + } + + /** + * Check if token is part of a class selector (e.g. `.abc`) + * @param {Number} i Token's index number + * @returns {Number} Length of the class selector + */ + function checkClass(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (tokens[i].class_l) return tokens[i].class_l; + + if (tokens[i++].type !== TokenType.FullStop) return 0; + + if (l = checkIdentOrInterpolation(i)) i += l;else return 0; + + while (i < tokensLength) { + if (l = checkIdentOrInterpolation(i)) i += l;else break; + } + + tokens[start].classEnd = i; + + return i - start; + } + + /** + * Get node with a class selector + * @returns {Array} `['class', ['ident', x]]` where x is a class's + * identifier (without `.`, e.g. `abc`). + */ + function getClass() { + var startPos = pos; + var type = NodeType.ClassType; + var token = tokens[startPos]; + var line = token.ln; + var column = token.col; + var content = []; + var end = token.classEnd; + + // Skip `.` + pos++; + + while (pos < end) { + if (checkIdentOrInterpolation(pos)) { + content = content.concat(getIdentOrInterpolation()); + } else break; + } + + return newNode(type, content, line, column); + } + + function checkCombinator(i) { + if (i >= tokensLength) return 0; + + var l = void 0; + if (l = checkCombinator1(i)) tokens[i].combinatorType = 1;else if (l = checkCombinator2(i)) tokens[i].combinatorType = 2;else if (l = checkCombinator3(i)) tokens[i].combinatorType = 3; + + return l; + } + + function getCombinator() { + var type = tokens[pos].combinatorType; + if (type === 1) return getCombinator1(); + if (type === 2) return getCombinator2(); + if (type === 3) return getCombinator3(); + } + /** + * (1) `||` + */ + function checkCombinator1(i) { + if (tokens[i].type === TokenType.VerticalLine && tokens[i + 1].type === TokenType.VerticalLine) return 2;else return 0; + } + + function getCombinator1() { + var type = NodeType.CombinatorType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = '||'; + + pos += 2; + return newNode(type, content, line, column); + } + + /** + * (1) `>` + * (2) `+` + * (3) `~` + */ + function checkCombinator2(i) { + var type = tokens[i].type; + if (type === TokenType.PlusSign || type === TokenType.GreaterThanSign || type === TokenType.Tilde) return 1;else return 0; + } + + function getCombinator2() { + var type = NodeType.CombinatorType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = tokens[pos++].value; + + return newNode(type, content, line, column); + } + + /** + * (1) `/panda/` + */ + function checkCombinator3(i) { + var start = i; + + if (tokens[i].type === TokenType.Solidus) i++;else return 0; + + var l = void 0; + if (l = checkIdent(i)) i += l;else return 0; + + if (tokens[i].type === TokenType.Solidus) i++;else return 0; + + return i - start; + } + + function getCombinator3() { + var type = NodeType.CombinatorType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + + // Skip `/`. + pos++; + var ident = getIdent(); + + // Skip `/`. + pos++; + + var content = '/' + ident.content + '/'; + + return newNode(type, content, line, column); + } + + /** + * Check if token is a multiline comment. + * @param {Number} i Token's index number + * @returns {Number} `1` if token is a multiline comment, otherwise `0` + */ + function checkCommentML(i) { + return i < tokensLength && tokens[i].type === TokenType.CommentML ? 1 : 0; + } + + /** + * Get node with a multiline comment + * @returns {Array} `['commentML', x]` where `x` + * is the comment's text (without `/*` and `* /`). + */ + function getCommentML() { + var startPos = pos; + var s = tokens[pos].value.substring(2); + var l = s.length; + var token = tokens[startPos]; + var line = token.ln; + var column = token.col; + + if (s.charAt(l - 2) === '*' && s.charAt(l - 1) === '/') s = s.substring(0, l - 2); + + var end = getLastPosition(s, line, column, 2); + if (end[0] === line) end[1] += 2; + pos++; + + return newNode(NodeType.CommentMLType, s, token.ln, token.col, end); + } + + /** + * Check if token is part of a single-line comment. + * @param {Number} i Token's index number + * @returns {Number} `1` if token is a single-line comment, otherwise `0` + */ + function checkCommentSL(i) { + return i < tokensLength && tokens[i].type === TokenType.CommentSL ? 1 : 0; + } + + /** + * Get node with a single-line comment. + * @returns {Array} `['commentSL', x]` where `x` is comment's message + * (without `//`) + */ + function getCommentSL() { + var startPos = pos; + var x = void 0; + var token = tokens[startPos]; + var line = token.ln; + var column = token.col; + + x = tokens[pos++].value.substring(2); + var end = getLastPosition(x, line, column + 2); + + return newNode(NodeType.CommentSLType, x, token.ln, token.col, end); + } + + /** + * Check if token is part of a condition + * (e.g. `@if ...`, `@else if ...` or `@else ...`). + * @param {Number} i Token's index number + * @returns {Number} Length of the condition + */ + function checkCondition(i) { + var start = i; + var l = void 0; + var _i = void 0; + var s = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkAtkeyword(i)) i += l;else return 0; + + if (['if', 'else'].indexOf(tokens[start + 1].value) < 0) return 0; + + while (i < tokensLength) { + if (l = checkBlock(i)) break; + + s = checkSC(i); + _i = i + s; + + if (l = _checkCondition(_i)) i += l + s;else break; + } + + return i - start; + } + + function _checkCondition(i) { + return checkVariable(i) || checkNumber(i) || checkInterpolation(i) || checkIdent(i) || checkOperator(i) || checkCombinator(i) || checkString(i); + } + + /** + * Get node with a condition. + * @returns {Array} `['condition', x]` + */ + function getCondition() { + var startPos = pos; + var x = []; + var s; + var _pos; + + x.push(getAtkeyword()); + + while (pos < tokensLength) { + if (checkBlock(pos)) break; + + s = checkSC(pos); + _pos = pos + s; + + if (!_checkCondition(_pos)) break; + + if (s) x = x.concat(getSC()); + x.push(_getCondition()); + } + + var token = tokens[startPos]; + return newNode(NodeType.ConditionType, x, token.ln, token.col); + } + + function _getCondition() { + if (checkVariable(pos)) return getVariable(); + if (checkNumber(pos)) return getNumber(); + if (checkInterpolation(pos)) return getInterpolation(); + if (checkIdent(pos)) return getIdent(); + if (checkOperator(pos)) return getOperator(); + if (checkCombinator(pos)) return getCombinator(); + if (checkString(pos)) return getString(); + } + + /** + * Check if token is part of a conditional statement + * (e.g. `@if ... {} @else if ... {} @else ... {}`). + * @param {Number} i Token's index number + * @returns {Number} Length of the condition + */ + function checkConditionalStatement(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkCondition(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkBlock(i)) i += l;else return 0; + + return i - start; + } + + /** + * Get node with a condition. + * @returns {Array} `['condition', x]` + */ + function getConditionalStatement() { + var startPos = pos; + var x = []; + + x.push(getCondition()); + x = x.concat(getSC()); + x.push(getBlock()); + + var token = tokens[startPos]; + return newNode(NodeType.ConditionalStatementType, x, token.ln, token.col); + } + + /** + * Check if token is part of a declaration (property-value pair) + * @param {Number} i Token's index number + * @returns {Number} Length of the declaration + */ + function checkDeclaration(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkProperty(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkPropertyDelim(i)) i++;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkValue(i)) i += l;else return 0; + + return i - start; + } + + /** + * Get node with a declaration + * @returns {Array} `['declaration', ['property', x], ['propertyDelim'], + * ['value', y]]` + */ + function getDeclaration() { + var startPos = pos; + var x = []; + + x.push(getProperty()); + x = x.concat(getSC()); + x.push(getPropertyDelim()); + x = x.concat(getSC()); + x.push(getValue()); + + var token = tokens[startPos]; + return newNode(NodeType.DeclarationType, x, token.ln, token.col); + } + + /** + * @param {number} i Token's index number + * @returns {number} Length of the declaration + */ + function checkSingleValueDeclaration(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkProperty(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkPropertyDelim(i)) i++;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkSingleValue(i)) i += l;else return 0; + + return i - start; + } + + /** + * Get node with a declaration + * @returns {Array} `['declaration', ['property', x], ['propertyDelim'], + * ['value', y]]` + */ + function getSingleValueDeclaration() { + var startPos = pos; + var x = []; + + x.push(getProperty()); + x = x.concat(getSC()); + x.push(getPropertyDelim()); + x = x.concat(getSC()); + x.push(getSingleValue()); + + var token = tokens[startPos]; + return newNode(NodeType.DeclarationType, x, token.ln, token.col); + } + + /** + * Check if token is a semicolon + * @param {Number} i Token's index number + * @returns {Number} `1` if token is a semicolon, otherwise `0` + */ + function checkDeclDelim(i) { + return i < tokensLength && tokens[i].type === TokenType.Semicolon ? 1 : 0; + } + + /** + * Get node with a semicolon + * @returns {Array} `['declDelim']` + */ + function getDeclDelim() { + var startPos = pos++; + + var token = tokens[startPos]; + return newNode(NodeType.DeclDelimType, ';', token.ln, token.col); + } + + /** + * Check if token if part of `!default` word. + * @param {Number} i Token's index number + * @returns {Number} Length of the `!default` word + */ + function checkDefault(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength || tokens[i++].type !== TokenType.ExclamationMark) return 0; + + if (l = checkSC(i)) i += l; + + if (tokens[i].value === 'default') { + tokens[start].defaultEnd = i; + return i - start + 1; + } else { + return 0; + } + } + + /** + * Get node with a `!default` word + * @returns {Array} `['default', sc]` where `sc` is optional whitespace + */ + function getDefault() { + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = joinValues(pos, token.defaultEnd); + + pos = token.defaultEnd + 1; + + return newNode(NodeType.DefaultType, content, line, column); + } + + /** + * Check if token is a comma + * @param {Number} i Token's index number + * @returns {Number} `1` if token is a comma, otherwise `0` + */ + function checkDelim(i) { + return i < tokensLength && tokens[i].type === TokenType.Comma ? 1 : 0; + } + + /** + * Get node with a comma + * @returns {Array} `['delim']` + */ + function getDelim() { + var startPos = pos; + + pos++; + + var token = tokens[startPos]; + return newNode(NodeType.DelimType, ',', token.ln, token.col); + } + + /** + * Check if token is part of a number with dimension unit (e.g. `10px`) + * @param {Number} i Token's index number + * @return {Number} + */ + function checkDimension(i) { + var ln = checkNumber(i); + var li = void 0; + + if (i >= tokensLength || !ln || i + ln >= tokensLength) return 0; + + return (li = checkUnit(i + ln)) ? ln + li : 0; + } + + /** + * Get node of a number with dimension unit + * @return {Node} + */ + function getDimension() { + var type = NodeType.DimensionType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = [getNumber(), getUnit()]; + + return newNode(type, content, line, column); + } + + /** + * Check if token is unit + * @param {Number} i Token's index number + * @return {Number} + */ + function checkUnit(i) { + var units = ['em', 'ex', 'ch', 'rem', 'vh', 'vw', 'vmin', 'vmax', 'px', 'mm', 'q', 'cm', 'in', 'pt', 'pc', 'deg', 'grad', 'rad', 'turn', 's', 'ms', 'Hz', 'kHz', 'dpi', 'dpcm', 'dppx']; + + return units.indexOf(tokens[i].value) !== -1 ? 1 : 0; + } + + /** + * Get unit node of type ident + * @return {Node} An ident node containing the unit value + */ + function getUnit() { + var type = NodeType.IdentType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = token.value; + + pos++; + + return newNode(type, content, line, column); + } + + /** + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkExpression(i) { + var start = i; + + if (i >= tokensLength || tokens[i++].value !== 'expression' || i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis) return 0; + + return tokens[i].right - start + 1; + } + + /** + * @returns {Array} + */ + function getExpression() { + var startPos = pos; + var e; + var token = tokens[startPos]; + var line = token.ln; + var column = token.col; + + pos++; + + e = joinValues(pos + 1, tokens[pos].right - 1); + var end = getLastPosition(e, line, column, 1); + if (end[0] === line) end[1] += 11; + pos = tokens[pos].right + 1; + + return newNode(NodeType.ExpressionType, e, token.ln, token.col, end); + } + + function checkExtend(i) { + var l = 0; + + if (l = checkExtend1(i)) tokens[i].extend_child = 1;else if (l = checkExtend2(i)) tokens[i].extend_child = 2; + + return l; + } + + function getExtend() { + var type = tokens[pos].extend_child; + + if (type === 1) return getExtend1();else if (type === 2) return getExtend2(); + } + + /** + * Checks if token is part of an extend with `!optional` flag. + * @param {Number} i + */ + function checkExtend1(i) { + var start = i; + var l; + + if (i >= tokensLength) return 0; + + if (l = checkAtkeyword(i)) i += l;else return 0; + + if (tokens[start + 1].value !== 'extend') return 0; + + if (l = checkSC(i)) i += l;else return 0; + + if (l = checkSelectorsGroup(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l;else return 0; + + if (l = checkOptional(i)) i += l;else return 0; + + return i - start; + } + + function getExtend1() { + var startPos = pos; + var x = [].concat([getAtkeyword()], getSC(), getSelectorsGroup(), getSC(), [getOptional()]); + + var token = tokens[startPos]; + return newNode(NodeType.ExtendType, x, token.ln, token.col); + } + + /** + * Checks if token is part of an extend without `!optional` flag. + * @param {Number} i + */ + function checkExtend2(i) { + var start = i; + var l; + + if (i >= tokensLength) return 0; + + if (l = checkAtkeyword(i)) i += l;else return 0; + + if (tokens[start + 1].value !== 'extend') return 0; + + if (l = checkSC(i)) i += l;else return 0; + + if (l = checkSelectorsGroup(i)) i += l;else return 0; + + return i - start; + } + + function getExtend2() { + var startPos = pos; + var x = [].concat([getAtkeyword()], getSC(), getSelectorsGroup()); + var token = tokens[startPos]; + return newNode(NodeType.ExtendType, x, token.ln, token.col); + } + + /** + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkFunction(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkIdentOrInterpolation(i)) i += l;else return 0; + + return i < tokensLength && tokens[i].type === TokenType.LeftParenthesis ? tokens[i].right - start + 1 : 0; + } + + /** + * @returns {Array} + */ + function getFunction() { + var startPos = pos; + var x = getIdentOrInterpolation(); + var body = void 0; + + body = getArguments(); + + x.push(body); + + var token = tokens[startPos]; + return newNode(NodeType.FunctionType, x, token.ln, token.col); + } + + /** + * @returns {Array} + */ + function getArguments() { + var startPos = pos; + var x = []; + var body = void 0; + var token = tokens[startPos]; + var line = token.ln; + var column = token.col; + + pos++; + + while (pos < tokensLength && tokens[pos].type !== TokenType.RightParenthesis) { + if (checkSingleValueDeclaration(pos)) x.push(getSingleValueDeclaration());else if (checkArgument(pos)) { + body = getArgument(); + if (typeof body.content === 'string') x.push(body);else x = x.concat(body); + } else if (checkClass(pos)) x.push(getClass());else throwError(); + } + + var end = getLastPosition(x, line, column, 1); + pos++; + + return newNode(NodeType.ArgumentsType, x, token.ln, token.col, end); + } + + /** + * Check if token is part of an identifier + * @param {Number} i Token's index number + * @returns {Number} Length of the identifier + */ + function checkIdent(i) { + var start = i; + + if (i >= tokensLength) return 0; + + // Check if token is part of a negative number + if (tokens[i].type === TokenType.HyphenMinus && tokens[i + 1].type === TokenType.DecimalNumber) return 0; + + if (tokens[i].type === TokenType.HyphenMinus) i++; + + if (checkInterpolation(i)) { + tokens[start].ident_last = i - 1; + return i - start; + } + + if (tokens[i].type === TokenType.LowLine || tokens[i].type === TokenType.Identifier) i++;else return 0; + + for (; i < tokensLength; i++) { + if (tokens[i].type !== TokenType.HyphenMinus && tokens[i].type !== TokenType.LowLine && tokens[i].type !== TokenType.Identifier && tokens[i].type !== TokenType.DecimalNumber) break; + } + + tokens[start].ident_last = i - 1; + + return i - start; + } + + /** + * Get node with an identifier + * @returns {Array} `['ident', x]` where `x` is identifier's name + */ + function getIdent() { + var startPos = pos; + var x = joinValues(pos, tokens[pos].ident_last); + + pos = tokens[pos].ident_last + 1; + + var token = tokens[startPos]; + return newNode(NodeType.IdentType, x, token.ln, token.col); + } + + /** + * @param {number} i Token's index number + * @returns {number} Length of the identifier + */ + function checkPartialIdent(i) { + var start = i; + + if (i >= tokensLength) return 0; + + for (; i < tokensLength; i++) { + if (tokens[i].type !== TokenType.HyphenMinus && tokens[i].type !== TokenType.LowLine && tokens[i].type !== TokenType.Identifier && tokens[i].type !== TokenType.DecimalNumber) break; + } + + tokens[start].ident_last = i - 1; + + return i - start; + } + + function checkIdentOrInterpolation(i) { + var start = i; + var l = void 0; + var prevIsInterpolation = false; + + while (i < tokensLength) { + if (l = checkInterpolation(i)) { + tokens[i].ii_type = 1; + i += l; + prevIsInterpolation = true; + } else if (l = checkIdent(i)) { + tokens[i].ii_type = 2; + i += l; + prevIsInterpolation = false; + } else if (prevIsInterpolation && (l = checkPartialIdent(i))) { + tokens[i].ii_type = 3; + i += l; + prevIsInterpolation = false; + } else break; + } + + return i - start; + } + + function getIdentOrInterpolation() { + var x = []; + + while (pos < tokensLength) { + var tokenType = tokens[pos].ii_type; + + if (tokenType === 1) { + x.push(getInterpolation()); + } else if (tokenType === 2 || tokenType === 3) { + x.push(getIdent()); + } else break; + } + + return x; + } + + /** + * Check if token is part of `!important` word + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkImportant(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength || tokens[i++].type !== TokenType.ExclamationMark) return 0; + + if (l = checkSC(i)) i += l; + + if (tokens[i].value === 'important') { + tokens[start].importantEnd = i; + return i - start + 1; + } else { + return 0; + } + } + + /** + * Get node with `!important` word + * @returns {Array} `['important', sc]` where `sc` is optional whitespace + */ + function getImportant() { + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = joinValues(pos, token.importantEnd); + + pos = token.importantEnd + 1; + + return newNode(NodeType.ImportantType, content, line, column); + } + + /** + * Check if token is part of an included mixin (`@include` or `@extend` + * directive). + * @param {Number} i Token's index number + * @returns {Number} Length of the included mixin + */ + function checkInclude(i) { + var l; + + if (i >= tokensLength) return 0; + + if (l = checkInclude1(i)) tokens[i].include_type = 1;else if (l = checkInclude2(i)) tokens[i].include_type = 2;else if (l = checkInclude3(i)) tokens[i].include_type = 3;else if (l = checkInclude4(i)) tokens[i].include_type = 4;else if (l = checkInclude5(i)) tokens[i].include_type = 5; + + return l; + } + + /** + * Check if token is part of `!global` word + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkGlobal(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength || tokens[i++].type !== TokenType.ExclamationMark) return 0; + + if (l = checkSC(i)) i += l; + + if (tokens[i].value === 'global') { + tokens[start].globalEnd = i; + return i - start + 1; + } else { + return 0; + } + } + + /** + * Get node with `!global` word + */ + function getGlobal() { + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = joinValues(pos, token.globalEnd); + + pos = token.globalEnd + 1; + + return newNode(NodeType.GlobalType, content, line, column); + } + + /** + * Get node with included mixin + * @returns {Array} `['include', x]` + */ + function getInclude() { + switch (tokens[pos].include_type) { + case 1: + return getInclude1(); + case 2: + return getInclude2(); + case 3: + return getInclude3(); + case 4: + return getInclude4(); + case 5: + return getInclude5(); + } + } + + /** + * Get node with included mixin with keyfames selector like + * `@include nani(foo) { 0% {}}` + * @param {Number} i Token's index number + * @returns {Number} Length of the include + */ + function checkInclude1(i) { + var start = i; + var l = void 0; + + if (l = checkAtkeyword(i)) i += l;else return 0; + + if (tokens[start + 1].value !== 'include') return 0; + + if (l = checkSC(i)) i += l;else return 0; + + if (l = checkIdentOrInterpolation(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkArguments(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkKeyframesBlocks(i)) i += l;else return 0; + + return i - start; + } + + /** + * Get node with included mixin with keyfames selector like + * `@include nani(foo) { 0% {}}` + * @returns {Array} `['include', ['atkeyword', x], sc, ['selector', y], sc, + * ['arguments', z], sc, ['block', q], sc` where `x` is `include` or + * `extend`, `y` is mixin's identifier (selector), `z` are arguments + * passed to the mixin, `q` is block passed to the mixin containing a + * ruleset > selector > keyframesSelector, and `sc` are optional + * whitespaces + */ + function getInclude1() { + var startPos = pos; + var x = [].concat(getAtkeyword(), getSC(), getIdentOrInterpolation(), getSC(), getArguments(), getSC(), getKeyframesBlocks()); + + var token = tokens[startPos]; + return newNode(NodeType.IncludeType, x, token.ln, token.col); + } + + /** + * Check if token is part of an included mixin like `@include nani(foo) {...}` + * @param {Number} i Token's index number + * @returns {Number} Length of the include + */ + function checkInclude2(i) { + var start = i; + var l = void 0; + + if (l = checkAtkeyword(i)) i += l;else return 0; + + if (tokens[start + 1].value !== 'include') return 0; + + if (l = checkSC(i)) i += l;else return 0; + + if (l = checkIdentOrInterpolation(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkArguments(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkBlock(i)) i += l;else return 0; + + return i - start; + } + + /** + * Get node with included mixin like `@include nani(foo) {...}` + * @returns {Array} `['include', ['atkeyword', x], sc, ['selector', y], sc, + * ['arguments', z], sc, ['block', q], sc` where `x` is `include` or + * `extend`, `y` is mixin's identifier (selector), `z` are arguments + * passed to the mixin, `q` is block passed to the mixin and `sc` + * are optional whitespaces + */ + function getInclude2() { + var startPos = pos; + var x = [].concat(getAtkeyword(), getSC(), getIdentOrInterpolation(), getSC(), getArguments(), getSC(), getBlock()); + + var token = tokens[startPos]; + return newNode(NodeType.IncludeType, x, token.ln, token.col); + } + + /** + * Check if token is part of an included mixin like `@include nani(foo)` + * @param {Number} i Token's index number + * @returns {Number} Length of the include + */ + function checkInclude3(i) { + var start = i; + var l = void 0; + + if (l = checkAtkeyword(i)) i += l;else return 0; + + if (tokens[start + 1].value !== 'include') return 0; + + if (l = checkSC(i)) i += l;else return 0; + + if (l = checkIdentOrInterpolation(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkArguments(i)) i += l;else return 0; + + return i - start; + } + + /** + * Get node with included mixin like `@include nani(foo)` + * @returns {Array} `['include', ['atkeyword', x], sc, ['selector', y], sc, + * ['arguments', z], sc]` where `x` is `include` or `extend`, `y` is + * mixin's identifier (selector), `z` are arguments passed to the + * mixin and `sc` are optional whitespaces + */ + function getInclude3() { + var startPos = pos; + var x = [].concat(getAtkeyword(), getSC(), getIdentOrInterpolation(), getSC(), getArguments()); + + var token = tokens[startPos]; + return newNode(NodeType.IncludeType, x, token.ln, token.col); + } + + /** + * Check if token is part of an included mixin with a content block passed + * as an argument (e.g. `@include nani {...}`) + * @param {Number} i Token's index number + * @returns {Number} Length of the mixin + */ + function checkInclude4(i) { + var start = i; + var l = void 0; + + if (l = checkAtkeyword(i)) i += l;else return 0; + + if (tokens[start + 1].value !== 'include') return 0; + + if (l = checkSC(i)) i += l;else return 0; + + if (l = checkIdentOrInterpolation(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkBlock(i)) i += l;else return 0; + + return i - start; + } + + /** + * Get node with an included mixin with a content block passed + * as an argument (e.g. `@include nani {...}`) + * @returns {Array} `['include', x]` + */ + function getInclude4() { + var startPos = pos; + var x = [].concat(getAtkeyword(), getSC(), getIdentOrInterpolation(), getSC(), getBlock()); + + var token = tokens[startPos]; + return newNode(NodeType.IncludeType, x, token.ln, token.col); + } + + /** + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkInclude5(i) { + var start = i; + var l = void 0; + + if (l = checkAtkeyword(i)) i += l;else return 0; + + if (tokens[start + 1].value !== 'include') return 0; + + if (l = checkSC(i)) i += l;else return 0; + + if (l = checkIdentOrInterpolation(i)) i += l;else return 0; + + return i - start; + } + + /** + * @returns {Array} `['include', x]` + */ + function getInclude5() { + var startPos = pos; + var x = [].concat(getAtkeyword(), getSC(), getIdentOrInterpolation()); + + var token = tokens[startPos]; + return newNode(NodeType.IncludeType, x, token.ln, token.col); + } + + /** + * Check if token is part of an interpolated variable (e.g. `#{$nani}`). + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkInterpolation(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (tokens[i].type !== TokenType.NumberSign || !tokens[i + 1] || tokens[i + 1].type !== TokenType.LeftCurlyBracket) return 0; + + i += 2; + + while (tokens[i].type !== TokenType.RightCurlyBracket) { + if (l = checkArgument(i)) i += l;else return 0; + } + + return tokens[i].type === TokenType.RightCurlyBracket ? i - start + 1 : 0; + } + + /** + * Get node with an interpolated variable + * @returns {Array} `['interpolation', x]` + */ + function getInterpolation() { + var startPos = pos; + var x = []; + var token = tokens[startPos]; + var line = token.ln; + var column = token.col; + + // Skip `#{`: + pos += 2; + + while (pos < tokensLength && tokens[pos].type !== TokenType.RightCurlyBracket) { + var body = getArgument(); + if (typeof body.content === 'string') x.push(body);else x = x.concat(body); + } + + var end = getLastPosition(x, line, column, 1); + + // Skip `}`: + pos++; + + return newNode(NodeType.InterpolationType, x, token.ln, token.col, end); + } + + /** + * Check a single keyframe block - `5% {}` + * @param {Number} i + * @returns {Number} + */ + function checkKeyframesBlock(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkKeyframesSelectorsGroup(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkBlock(i)) i += l;else return 0; + + return i - start; + } + + /** + * Get a single keyframe block - `5% {}` + * @returns {Node} + */ + function getKeyframesBlock() { + var type = NodeType.RulesetType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = [].concat(getKeyframesSelectorsGroup(), getSC(), [getBlock()]); + + return newNode(type, content, line, column); + } + + /** + * Check all keyframe blocks - `5% {} 100% {}` + * @param {Number} i + * @returns {Number} + */ + function checkKeyframesBlocks(i) { + var start = i; + var l = void 0; + + if (i < tokensLength && tokens[i].type === TokenType.LeftCurlyBracket) i++;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkKeyframesBlock(i)) i += l;else return 0; + + while (tokens[i].type !== TokenType.RightCurlyBracket) { + if (l = checkSC(i)) i += l;else if (l = checkKeyframesBlock(i)) i += l;else break; + } + + if (i < tokensLength && tokens[i].type === TokenType.RightCurlyBracket) i++;else return 0; + + return i - start; + } + + /** + * Get all keyframe blocks - `5% {} 100% {}` + * @returns {Node} + */ + function getKeyframesBlocks() { + var type = NodeType.BlockType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + var keyframesBlocksEnd = token.right; + + // Skip `{`. + pos++; + + while (pos < keyframesBlocksEnd) { + if (checkSC(pos)) content = content.concat(getSC());else if (checkKeyframesBlock(pos)) content.push(getKeyframesBlock());else if (checkAtrule(pos)) content.push(getAtrule()); // @content + else break; + } + + var end = getLastPosition(content, line, column, 1); + + // Skip `}`. + pos++; + + return newNode(type, content, line, column, end); + } + + /** + * Check if token is part of a @keyframes rule. + * @param {Number} i Token's index number + * @return {Number} Length of the @keyframes rule + */ + function checkKeyframesRule(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkAtkeyword(i)) i += l;else return 0; + + var atruleName = joinValues2(i - l, l); + if (atruleName.indexOf('keyframes') === -1) return 0; + + if (l = checkSC(i)) i += l;else return 0; + + if (l = checkIdentOrInterpolation(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkKeyframesBlocks(i)) i += l;else return 0; + + return i - start; + } + + /** + * @return {Node} + */ + function getKeyframesRule() { + var type = NodeType.AtruleType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = [].concat([getAtkeyword()], getSC(), getIdentOrInterpolation(), getSC(), [getKeyframesBlocks()]); + + return newNode(type, content, line, column); + } + + /** + * Check a single keyframe selector - `5%`, `from` etc + * @param {Number} i + * @returns {Number} + */ + function checkKeyframesSelector(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkIdent(i)) { + // Valid selectors are only `from` and `to`. + var selector = joinValues2(i, l); + if (selector !== 'from' && selector !== 'to') return 0; + + i += l; + tokens[start].keyframesSelectorType = 1; + } else if (l = checkPercentage(i)) { + i += l; + tokens[start].keyframesSelectorType = 2; + } else if (l = checkInterpolation(i)) { + i += l; + tokens[start].keyframesSelectorType = 3; + } else { + return 0; + } + + return i - start; + } + + /** + * Get a single keyframe selector + * @returns {Node} + */ + function getKeyframesSelector() { + var keyframesSelectorType = NodeType.KeyframesSelectorType; + var selectorType = NodeType.SelectorType; + + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + if (token.keyframesSelectorType === 1) { + content.push(getIdent()); + } else if (token.keyframesSelectorType === 2) { + content.push(getPercentage()); + } else if (token.keyframesSelectorType === 3) { + content.push(getInterpolation()); + } + + var keyframesSelector = newNode(keyframesSelectorType, content, line, column); + return newNode(selectorType, [keyframesSelector], line, column); + } + + /** + * Check the keyframe's selector groups + * @param {Number} i + * @returns {Number} + */ + function checkKeyframesSelectorsGroup(i) { + var start = i; + var l = void 0; + + if (l = checkKeyframesSelector(i)) i += l;else return 0; + + while (i < tokensLength) { + var sb = checkSC(i); + var c = checkDelim(i + sb); + if (!c) break; + var sa = checkSC(i + sb + c); + if (l = checkKeyframesSelector(i + sb + c + sa)) i += sb + c + sa + l;else break; + } + + tokens[start].selectorsGroupEnd = i; + + return i - start; + } + + /** + * Get the keyframe's selector groups + * @returns {Array} An array of keyframe selectors + */ + function getKeyframesSelectorsGroup() { + var selectorsGroup = []; + var selectorsGroupEnd = tokens[pos].selectorsGroupEnd; + + selectorsGroup.push(getKeyframesSelector()); + + while (pos < selectorsGroupEnd) { + selectorsGroup = selectorsGroup.concat(getSC()); + selectorsGroup.push(getDelim()); + selectorsGroup = selectorsGroup.concat(getSC()); + selectorsGroup.push(getKeyframesSelector()); + } + + return selectorsGroup; + } + + /** + * Check if token is part of a loop. + * @param {Number} i Token's index number + * @returns {Number} Length of the loop + */ + function checkLoop(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkAtkeyword(i)) i += l;else return 0; + + if (['for', 'each', 'while'].indexOf(tokens[start + 1].value) < 0) return 0; + + while (i < tokensLength) { + if (l = checkBlock(i)) { + i += l; + break; + } else if (l = checkVariable(i) || checkNumber(i) || checkInterpolation(i) || checkIdent(i) || checkSC(i) || checkOperator(i) || checkCombinator(i) || checkString(i)) i += l;else return 0; + } + + return i - start; + } + + /** + * Get node with a loop. + * @returns {Array} `['loop', x]` + */ + function getLoop() { + var startPos = pos; + var x = []; + + x.push(getAtkeyword()); + + while (pos < tokensLength) { + if (checkBlock(pos)) { + x.push(getBlock()); + break; + } else if (checkVariable(pos)) x.push(getVariable());else if (checkNumber(pos)) x.push(getNumber());else if (checkInterpolation(pos)) x.push(getInterpolation());else if (checkIdent(pos)) x.push(getIdent());else if (checkOperator(pos)) x.push(getOperator());else if (checkCombinator(pos)) x.push(getCombinator());else if (checkSC(pos)) x = x.concat(getSC());else if (checkString(pos)) x.push(getString()); + } + + var token = tokens[startPos]; + return newNode(NodeType.LoopType, x, token.ln, token.col); + } + + /** + * Check if token is part of a mixin + * @param {Number} i Token's index number + * @returns {Number} Length of the mixin + */ + function checkMixin(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if ((l = checkAtkeyword(i)) && tokens[i + 1].value === 'mixin') i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkIdentOrInterpolation(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkArguments(i)) i += l; + + if (l = checkSC(i)) i += l; + + if (l = checkBlock(i)) i += l;else return 0; + + return i - start; + } + + /** + * Get node with a mixin + * @returns {Array} `['mixin', x]` + */ + function getMixin() { + var startPos = pos; + var x = [getAtkeyword()]; + + x = x.concat(getSC()); + + if (checkIdentOrInterpolation(pos)) x = x.concat(getIdentOrInterpolation()); + + x = x.concat(getSC()); + + if (checkArguments(pos)) x.push(getArguments()); + + x = x.concat(getSC()); + + if (checkBlock(pos)) x.push(getBlock()); + + var token = tokens[startPos]; + return newNode(NodeType.MixinType, x, token.ln, token.col); + } + + /** + * Check if token is a namespace sign (`|`) + * @param {Number} i Token's index number + * @returns {Number} `1` if token is `|`, `0` if not + */ + function checkNamespace(i) { + return i < tokensLength && tokens[i].type === TokenType.VerticalLine ? 1 : 0; + } + + /** + * Get node with a namespace sign + * @returns {Array} `['namespace']` + */ + function getNamespace() { + var startPos = pos; + + pos++; + + var token = tokens[startPos]; + return newNode(NodeType.NamespaceType, '|', token.ln, token.col); + } + + /** + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkNmName2(i) { + if (tokens[i].type === TokenType.Identifier) return 1;else if (tokens[i].type !== TokenType.DecimalNumber) return 0; + + i++; + + return i < tokensLength && tokens[i].type === TokenType.Identifier ? 2 : 1; + } + + /** + * @returns {String} + */ + function getNmName2() { + var s = tokens[pos].value; + + if (tokens[pos++].type === TokenType.DecimalNumber && pos < tokensLength && tokens[pos].type === TokenType.Identifier) s += tokens[pos++].value; + + return s; + } + + /** + * Check if token is part of a number + * @param {Number} i Token's index number + * @returns {Number} Length of number + */ + function checkNumber(i) { + if (i >= tokensLength) return 0; + + if (tokens[i].number_l) return tokens[i].number_l; + + // `10`: + if (i < tokensLength && tokens[i].type === TokenType.DecimalNumber && (!tokens[i + 1] || tokens[i + 1] && tokens[i + 1].type !== TokenType.FullStop)) { + tokens[i].number_l = 1; + return 1; + } + + // `10.`: + if (i < tokensLength && tokens[i].type === TokenType.DecimalNumber && tokens[i + 1] && tokens[i + 1].type === TokenType.FullStop && (!tokens[i + 2] || tokens[i + 2].type !== TokenType.DecimalNumber)) { + tokens[i].number_l = 2; + return 2; + } + + // `.10`: + if (i < tokensLength && tokens[i].type === TokenType.FullStop && tokens[i + 1].type === TokenType.DecimalNumber) { + tokens[i].number_l = 2; + return 2; + } + + // `10.10`: + if (i < tokensLength && tokens[i].type === TokenType.DecimalNumber && tokens[i + 1] && tokens[i + 1].type === TokenType.FullStop && tokens[i + 2] && tokens[i + 2].type === TokenType.DecimalNumber) { + tokens[i].number_l = 3; + return 3; + } + + return 0; + } + + /** + * Get node with number + * @returns {Array} `['number', x]` where `x` is a number converted + * to string. + */ + function getNumber() { + var s = ''; + var startPos = pos; + var l = tokens[pos].number_l; + + for (var j = 0; j < l; j++) { + s += tokens[pos + j].value; + } + + pos += l; + + var token = tokens[startPos]; + return newNode(NodeType.NumberType, s, token.ln, token.col); + } + + /** + * Check if token is an operator (`/`, `%`, `,`, `:` or `=`). + * @param {Number} i Token's index number + * @returns {Number} `1` if token is an operator, otherwise `0` + */ + function checkOperator(i) { + if (i >= tokensLength) return 0; + + switch (tokens[i].type) { + case TokenType.Solidus: + case TokenType.PercentSign: + case TokenType.Comma: + case TokenType.Colon: + case TokenType.EqualsSign: + case TokenType.EqualitySign: + case TokenType.InequalitySign: + case TokenType.LessThanSign: + case TokenType.GreaterThanSign: + case TokenType.Asterisk: + return 1; + } + + return 0; + } + + /** + * Get node with an operator + * @returns {Array} `['operator', x]` where `x` is an operator converted + * to string. + */ + function getOperator() { + var startPos = pos; + var x = tokens[pos++].value; + + var token = tokens[startPos]; + return newNode(NodeType.OperatorType, x, token.ln, token.col); + } + + /** + * Check if token is part of `!optional` word + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkOptional(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength || tokens[i++].type !== TokenType.ExclamationMark) return 0; + + if (l = checkSC(i)) i += l; + + if (tokens[i].value === 'optional') { + tokens[start].optionalEnd = i; + return i - start + 1; + } else { + return 0; + } + } + + /** + * Get node with `!optional` word + */ + function getOptional() { + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = joinValues(pos, token.optionalEnd); + + pos = token.optionalEnd + 1; + + return newNode(NodeType.OptionalType, content, line, column); + } + + /** + * Check if token is part of text inside parentheses, e.g. `(1)` + * @param {Number} i Token's index number + * @return {Number} + */ + function checkParentheses(i) { + if (i >= tokensLength) return 0; + + var start = i; + var right = tokens[i].right; + + if (tokens[i].type === TokenType.LeftParenthesis) i++;else return 0; + + if (i < right) { + var l = checkTsets(i); + if (l) i += l;else return 0; + } + + i++; + + return i - start; + } + + /** + * Get node with text inside parentheses, e.g. `(1)` + * @return {Node} + */ + function getParentheses() { + var type = NodeType.ParenthesesType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var tsets = []; + var right = token.right; + + pos++; + + if (pos < right) { + tsets = getTsets(); + } + + var end = getLastPosition(tsets, line, column, 1); + pos++; + + return newNode(type, tsets, line, column, end); + } + + /** + * Check if token is a parent selector, e.g. `&` + * @param {number} i Token's index number + * @return {number} + */ + function checkParentSelector(i) { + return i < tokensLength && tokens[i].type === TokenType.Ampersand ? 1 : 0; + } + + /** + * Get node with a parent selector + * @return {Node} + */ + function getParentSelector() { + var startPos = pos; + var token = tokens[startPos]; + + pos++; + + return newNode(NodeType.ParentSelectorType, '&', token.ln, token.col); + } + + /** + * Check if token is a parent selector extension, e.g. `&--foo-bar` + * @param {number} i Token's index number + * @returns {number} Length of the parent selector extension + */ + function checkParentSelectorExtension(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + while (i < tokensLength) { + if (l = checkIdentOrInterpolation(i) || checkPartialIdent(i)) i += l;else break; + } + + return i - start; + } + + /** + * Get parent selector extension node + * @return {Node} + */ + function getParentSelectorExtension() { + var type = NodeType.ParentSelectorExtensionType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + while (pos < tokensLength) { + if (checkIdentOrInterpolation(pos)) { + content = content.concat(getIdentOrInterpolation()); + } else if (checkPartialIdent(pos)) { + content.push(getIdent()); + } else break; + } + + return newNode(type, content, line, column); + } + + /** + * Check if token is a parent selector with an extension or not + * @param {number} i Token's index number + * @return {number} Length of the parent selector and extension if applicable + */ + function checkParentSelectorWithExtension(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkParentSelector(i)) i += l;else return 0; + + if (l = checkParentSelectorExtension(i)) i += l; + + return i - start; + } + + /** + * Get parent selector node and extension node if applicable + * @return {Array} + */ + function getParentSelectorWithExtension() { + var content = [getParentSelector()]; + + if (checkParentSelectorExtension(pos)) content.push(getParentSelectorExtension()); + + return content; + } + + /** + * Check if token is part of a number or an interpolation with a percent sign + * (e.g. `10%`). + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkPercentage(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkNumberOrInterpolation(i)) i += l;else return 0; + + if (i >= tokensLength) return 0; + + if (tokens[i].type !== TokenType.PercentSign) return 0; + + return i - start + 1; + } + + /** + * Get a percentage node that contains either a number or an interpolation + * @returns {Object} The percentage node + */ + function getPercentage() { + var startPos = pos; + var token = tokens[startPos]; + var line = token.ln; + var column = token.col; + var content = getNumberOrInterpolation(); + var end = getLastPosition(content, line, column, 1); + + // Skip % + pos++; + + return newNode(NodeType.PercentageType, content, token.ln, token.col, end); + } + + /** + * Check if token is a number or an interpolation + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkNumberOrInterpolation(i) { + var start = i; + var l = void 0; + + while (i < tokensLength) { + if (l = checkInterpolation(i) || checkNumber(i)) i += l;else break; + } + + return i - start; + } + + /** + * Get a number and/or interpolation node + * @returns {Array} An array containing a single or multiple nodes + */ + function getNumberOrInterpolation() { + var content = []; + + while (pos < tokensLength) { + if (checkInterpolation(pos)) content.push(getInterpolation());else if (checkNumber(pos)) content.push(getNumber());else break; + } + + return content; + } + + /** + * Check if token is part of a placeholder selector (e.g. `%abc`). + * @param {Number} i Token's index number + * @returns {Number} Length of the selector + */ + function checkPlaceholder(i) { + var l; + + if (i >= tokensLength) return 0; + + if (tokens[i].placeholder_l) return tokens[i].placeholder_l; + + if (tokens[i].type !== TokenType.PercentSign) return 0; + + if (l = checkIdentOrInterpolation(i + 1)) { + tokens[i].placeholder_l = l + 1; + return l + 1; + } else return 0; + } + + /** + * Get node with a placeholder selector + * @returns {Array} `['placeholder', ['ident', x]]` where x is a placeholder's + * identifier (without `%`, e.g. `abc`). + */ + function getPlaceholder() { + var startPos = pos; + + pos++; + + var x = getIdentOrInterpolation(); + + var token = tokens[startPos]; + return newNode(NodeType.PlaceholderType, x, token.ln, token.col); + } + + /** + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkProgid(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (joinValues2(i, 6) === 'progid:DXImageTransform.Microsoft.') i += 6;else return 0; + + if (l = checkIdentOrInterpolation(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (tokens[i].type === TokenType.LeftParenthesis) { + tokens[start].progid_end = tokens[i].right; + i = tokens[i].right + 1; + } else return 0; + + return i - start; + } + + /** + * @returns {Array} + */ + function getProgid() { + var startPos = pos; + var progid_end = tokens[pos].progid_end; + var x = joinValues(pos, progid_end); + + pos = progid_end + 1; + + var token = tokens[startPos]; + return newNode(NodeType.ProgidType, x, token.ln, token.col); + } + + /** + * Check if token is part of a property + * @param {Number} i Token's index number + * @returns {Number} Length of the property + */ + function checkProperty(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkVariable(i) || checkIdentOrInterpolation(i)) i += l;else return 0; + + return i - start; + } + + /** + * Get node with a property + * @returns {Array} `['property', x]` + */ + function getProperty() { + var startPos = pos; + var x = []; + + if (checkVariable(pos)) { + x.push(getVariable()); + } else { + x = x.concat(getIdentOrInterpolation()); + } + + var token = tokens[startPos]; + return newNode(NodeType.PropertyType, x, token.ln, token.col); + } + + /** + * Check if token is a colon + * @param {Number} i Token's index number + * @returns {Number} `1` if token is a colon, otherwise `0` + */ + function checkPropertyDelim(i) { + return i < tokensLength && tokens[i].type === TokenType.Colon ? 1 : 0; + } + + /** + * Get node with a colon + * @returns {Array} `['propertyDelim']` + */ + function getPropertyDelim() { + var startPos = pos; + + pos++; + + var token = tokens[startPos]; + return newNode(NodeType.PropertyDelimType, ':', token.ln, token.col); + } + + /** + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkPseudo(i) { + return checkPseudoe(i) || checkPseudoc(i); + } + + /** + * @returns {Array} + */ + function getPseudo() { + if (checkPseudoe(pos)) return getPseudoe(); + if (checkPseudoc(pos)) return getPseudoc(); + } + + /** + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkPseudoe(i) { + var l; + + if (i >= tokensLength || tokens[i++].type !== TokenType.Colon || i >= tokensLength || tokens[i++].type !== TokenType.Colon) return 0; + + return (l = checkIdentOrInterpolation(i)) ? l + 2 : 0; + } + + /** + * @returns {Array} + */ + function getPseudoe() { + var startPos = pos; + + pos += 2; + + var x = getIdentOrInterpolation(); + + var token = tokens[startPos]; + return newNode(NodeType.PseudoeType, x, token.ln, token.col); + } + + /** + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkPseudoc(i) { + var l; + + if (i >= tokensLength || tokens[i].type !== TokenType.Colon) return 0; + + if (l = checkPseudoClass3(i)) tokens[i].pseudoClassType = 3;else if (l = checkPseudoClass4(i)) tokens[i].pseudoClassType = 4;else if (l = checkPseudoClass5(i)) tokens[i].pseudoClassType = 5;else if (l = checkPseudoClass1(i)) tokens[i].pseudoClassType = 1;else if (l = checkPseudoClass2(i)) tokens[i].pseudoClassType = 2;else if (l = checkPseudoClass6(i)) tokens[i].pseudoClassType = 6;else return 0; + + return l; + } + + /** + * @returns {Array} + */ + function getPseudoc() { + var childType = tokens[pos].pseudoClassType; + if (childType === 1) return getPseudoClass1(); + if (childType === 2) return getPseudoClass2(); + if (childType === 3) return getPseudoClass3(); + if (childType === 4) return getPseudoClass4(); + if (childType === 5) return getPseudoClass5(); + if (childType === 6) return getPseudoClass6(); + } + + /** + * (-) `:not(panda)` + */ + function checkPseudoClass1(i) { + var start = i; + + // Skip `:`. + i++; + + if (i >= tokensLength) return 0; + + var l = void 0; + if (l = checkIdentOrInterpolation(i)) i += l;else return 0; + + if (i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis) return 0; + + var right = tokens[i].right; + + // Skip `(`. + i++; + + if (l = checkSelectorsGroup(i)) i += l;else return 0; + + if (i !== right) return 0; + + return right - start + 1; + } + + /** + * (-) `:not(panda)` + */ + function getPseudoClass1() { + var type = NodeType.PseudocType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + // Skip `:`. + pos++; + + content = content.concat(getIdentOrInterpolation()); + + { + var _type = NodeType.ArgumentsType; + var _token = tokens[pos]; + var _line = _token.ln; + var _column = _token.col; + + // Skip `(`. + pos++; + + var selectors = getSelectorsGroup(); + var end = getLastPosition(selectors, _line, _column, 1); + var args = newNode(_type, selectors, _line, _column, end); + content.push(args); + + // Skip `)`. + pos++; + } + + return newNode(type, content, line, column); + } + + /** + * (1) `:nth-child(odd)` + * (2) `:nth-child(even)` + * (3) `:lang(de-DE)` + */ + function checkPseudoClass2(i) { + var start = i; + var l = 0; + + // Skip `:`. + i++; + + if (i >= tokensLength) return 0; + + if (l = checkIdentOrInterpolation(i)) i += l;else return 0; + + if (i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis) return 0; + + var right = tokens[i].right; + + // Skip `(`. + i++; + + if (l = checkSC(i)) i += l; + + if (l = checkIdentOrInterpolation(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (i !== right) return 0; + + return i - start + 1; + } + + function getPseudoClass2() { + var type = NodeType.PseudocType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + // Skip `:`. + pos++; + + content = content.concat(getIdentOrInterpolation()); + + var l = tokens[pos].ln; + var c = tokens[pos].col; + var value = []; + + // Skip `(`. + pos++; + + value = value.concat(getSC()).concat(getIdentOrInterpolation()).concat(getSC()); + + var end = getLastPosition(value, l, c, 1); + var args = newNode(NodeType.ArgumentsType, value, l, c, end); + content.push(args); + + // Skip `)`. + pos++; + + return newNode(type, content, line, column); + } + + /** + * (-) `:nth-child(-3n + 2)` + */ + function checkPseudoClass3(i) { + var start = i; + var l = 0; + + // Skip `:`. + i++; + + if (i >= tokensLength) return 0; + + if (l = checkIdentOrInterpolation(i)) i += l;else return 0; + + if (i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis) return 0; + + var right = tokens[i].right; + + // Skip `(`. + i++; + + if (l = checkSC(i)) i += l; + + if (l = checkUnary(i)) i += l; + + if (l = checkNumberOrInterpolation(i)) i += l; + + if (i >= tokensLength) return 0; + if (tokens[i].value === 'n') i++;else return 0; + + if (l = checkSC(i)) i += l; + + if (i >= tokensLength) return 0; + + if (tokens[i].type === TokenType.PlusSign || tokens[i].type === TokenType.HyphenMinus) i++;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkNumberOrInterpolation(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (i !== right) return 0; + + return i - start + 1; + } + + function getPseudoClass3() { + var type = NodeType.PseudocType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + + // Skip `:`. + pos++; + + var content = getIdentOrInterpolation(); + + var l = tokens[pos].ln; + var c = tokens[pos].col; + var value = []; + + // Skip `(`. + pos++; + + if (checkUnary(pos)) value.push(getUnary()); + + if (checkNumberOrInterpolation(pos)) value = value.concat(getNumberOrInterpolation()); + + { + var _l = tokens[pos].ln; + var _c = tokens[pos].col; + var _content = tokens[pos].value; + var ident = newNode(NodeType.IdentType, _content, _l, _c); + value.push(ident); + pos++; + } + + value = value.concat(getSC()); + if (checkUnary(pos)) value.push(getUnary()); + value = value.concat(getSC()); + if (checkNumberOrInterpolation(pos)) value = value.concat(getNumberOrInterpolation()); + value = value.concat(getSC()); + + var end = getLastPosition(value, l, c, 1); + var args = newNode(NodeType.ArgumentsType, value, l, c, end); + content.push(args); + + // Skip `)`. + pos++; + + return newNode(type, content, line, column); + } + + /** + * (-) `:nth-child(-3n)` + */ + function checkPseudoClass4(i) { + var start = i; + var l = 0; + + // Skip `:`. + i++; + + if (i >= tokensLength) return 0; + + if (l = checkIdentOrInterpolation(i)) i += l;else return 0; + + if (i >= tokensLength) return 0; + if (tokens[i].type !== TokenType.LeftParenthesis) return 0; + + var right = tokens[i].right; + + // Skip `(`. + i++; + + if (l = checkSC(i)) i += l; + + // Check for leading unary `-` + if (l = checkUnary(i)) i += l; + + // Check for interpolation `#{i}` + if (l = checkInterpolation(i)) i += l; + + if (tokens[i].type === TokenType.DecimalNumber) i++; + + if (tokens[i].value === 'n') i++;else return 0; + + if (l = checkSC(i)) i += l; + + if (i !== right) return 0; + + return i - start + 1; + } + + function getPseudoClass4() { + var type = NodeType.PseudocType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + + // Skip `:`. + pos++; + + var content = getIdentOrInterpolation(); + + var l = tokens[pos].ln; + var c = tokens[pos].col; + var value = []; + + // Skip `(`. + pos++; + + value = value.concat(getSC()); + + if (checkUnary(pos)) value.push(getUnary()); + if (checkInterpolation(pos)) value.push(getInterpolation()); + if (checkNumber(pos)) value.push(getNumber()); + if (checkIdent(pos)) value.push(getIdent()); + value = value.concat(getSC()); + + var end = getLastPosition(value, l, c, 1); + var args = newNode(NodeType.ArgumentsType, value, l, c, end); + content.push(args); + + // Skip `)`. + pos++; + + return newNode(type, content, line, column); + } + + /** + * (-) `:nth-child(+8)` + */ + function checkPseudoClass5(i) { + var start = i; + var l = 0; + + // Skip `:`. + i++; + + if (i >= tokensLength) return 0; + + if (l = checkIdentOrInterpolation(i)) i += l;else return 0; + + if (i >= tokensLength) return 0; + if (tokens[i].type !== TokenType.LeftParenthesis) return 0; + + var right = tokens[i].right; + + // Skip `(`. + i++; + + if (l = checkSC(i)) i += l; + + if (l = checkUnary(i)) i += l; + if (tokens[i].type === TokenType.DecimalNumber) i++;else return 0; + + if (l = checkSC(i)) i += l; + + if (i !== right) return 0; + + return i - start + 1; + } + + function getPseudoClass5() { + var type = NodeType.PseudocType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + + // Skip `:`. + pos++; + + var content = getIdentOrInterpolation(); + + var l = tokens[pos].ln; + var c = tokens[pos].col; + var value = []; + + // Skip `(`. + pos++; + + if (checkUnary(pos)) value.push(getUnary()); + if (checkNumber(pos)) value.push(getNumber()); + value = value.concat(getSC()); + + var end = getLastPosition(value, l, c, 1); + var args = newNode(NodeType.ArgumentsType, value, l, c, end); + content.push(args); + + // Skip `)`. + pos++; + + return newNode(type, content, line, column); + } + + /** + * (-) `:checked` + */ + function checkPseudoClass6(i) { + var start = i; + var l = 0; + + // Skip `:`. + i++; + + if (i >= tokensLength) return 0; + + if (l = checkIdentOrInterpolation(i)) i += l;else return 0; + + return i - start; + } + + function getPseudoClass6() { + var type = NodeType.PseudocType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + + // Skip `:`. + pos++; + + var content = getIdentOrInterpolation(); + + return newNode(type, content, line, column); + } + + /** + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkRuleset(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkSelectorsGroup(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkBlock(i)) i += l;else return 0; + + return i - start; + } + + function getRuleset() { + var type = NodeType.RulesetType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + content = content.concat(getSelectorsGroup()); + content = content.concat(getSC()); + content.push(getBlock()); + + return newNode(type, content, line, column); + } + + /** + * Check if token is marked as a space (if it's a space or a tab + * or a line break). + * @param {Number} i + * @returns {Number} Number of spaces in a row starting with the given token. + */ + function checkS(i) { + return i < tokensLength && tokens[i].ws ? tokens[i].ws_last - i + 1 : 0; + } + + /** + * Get node with spaces + * @returns {Array} `['s', x]` where `x` is a string containing spaces + */ + function getS() { + var startPos = pos; + var x = joinValues(pos, tokens[pos].ws_last); + + pos = tokens[pos].ws_last + 1; + + var token = tokens[startPos]; + return newNode(NodeType.SType, x, token.ln, token.col); + } + + /** + * Check if token is a space or a comment. + * @param {Number} i Token's index number + * @returns {Number} Number of similar (space or comment) tokens + * in a row starting with the given token. + */ + function checkSC(i) { + if (i >= tokensLength) return 0; + + var l = void 0; + var lsc = 0; + + while (i < tokensLength) { + if (!(l = checkS(i)) && !(l = checkCommentML(i)) && !(l = checkCommentSL(i))) break; + i += l; + lsc += l; + } + + return lsc || 0; + } + + /** + * Get node with spaces and comments + * @returns {Array} Array containing nodes with spaces (if there are any) + * and nodes with comments (if there are any): + * `[['s', x]*, ['comment', y]*]` where `x` is a string of spaces + * and `y` is a comment's text (without `/*` and `* /`). + */ + function getSC() { + var sc = []; + + if (pos >= tokensLength) return sc; + + while (pos < tokensLength) { + if (checkS(pos)) sc.push(getS());else if (checkCommentML(pos)) sc.push(getCommentML());else if (checkCommentSL(pos)) sc.push(getCommentSL());else break; + } + + return sc; + } + + /** + * Check if token is part of a hexadecimal number (e.g. `#fff`) inside a simple + * selector + * @param {number} i Token's index number + * @return {number} + */ + function checkShash(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (tokens[i].type === TokenType.NumberSign) i++;else return 0; + + if (l = checkIdentOrInterpolation(i) || checkPartialIdent(i)) i += l;else return 0; + + while (i < tokensLength) { + if (l = checkIdentOrInterpolation(i) || checkPartialIdent(i)) i += l;else break; + } + + tokens[start].shashEnd = i; + + return i - start; + } + + /** + * Get node with a hexadecimal number (e.g. `#fff`) inside a simple selector + * @returns {Node} + */ + function getShash() { + var startPos = pos; + var type = NodeType.ShashType; + var token = tokens[startPos]; + var line = token.ln; + var column = token.col; + var end = token.shashEnd; + var content = []; + + // Skip `#` + pos++; + + while (pos < end) { + if (checkIdentOrInterpolation(pos)) { + content = content.concat(getIdentOrInterpolation()); + } else if (checkPartialIdent(pos)) { + content.push(getIdent()); + } else break; + } + + return newNode(type, content, line, column); + } + + /** + * Check if token is part of a string (text wrapped in quotes) + * @param {Number} i Token's index number + * @returns {Number} `1` if token is part of a string, `0` if not + */ + function checkString(i) { + if (i >= tokensLength) return 0; + + if (tokens[i].type === TokenType.StringSQ || tokens[i].type === TokenType.StringDQ) { + return 1; + } + + return 0; + } + + /** + * Get string's node + * @returns {Array} `['string', x]` where `x` is a string (including + * quotes). + */ + function getString() { + var startPos = pos; + var x = tokens[pos++].value; + + var token = tokens[startPos]; + return newNode(NodeType.StringType, x, token.ln, token.col); + } + + /** + * Validate stylesheet: it should consist of any number (0 or more) of + * rulesets (sets of rules with selectors), @-rules, whitespaces or + * comments. + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkStylesheet(i) { + var start = i; + var l = void 0; + + while (i < tokensLength) { + if (l = checkSC(i)) tokens[i].ss_child = 1;else if (l = checkRuleset(i)) tokens[i].ss_child = 2;else if (l = checkInclude(i)) tokens[i].ss_child = 3;else if (l = checkExtend(i)) tokens[i].ss_child = 4;else if (l = checkMixin(i)) tokens[i].ss_child = 5;else if (l = checkLoop(i)) tokens[i].ss_child = 6;else if (l = checkConditionalStatement(i)) tokens[i].ss_child = 7;else if (l = checkAtrule(i)) tokens[i].ss_child = 8;else if (l = checkDeclaration(i)) tokens[i].ss_child = 9;else if (l = checkDeclDelim(i)) tokens[i].ss_child = 10;else throwError(i); + + i += l; + } + + return i - start; + } + + /** + * @returns {Array} `['stylesheet', x]` where `x` is all stylesheet's + * nodes. + */ + function getStylesheet() { + var startPos = pos; + var x = []; + + while (pos < tokensLength) { + var childType = tokens[pos].ss_child; + + if (childType === 1) x = x.concat(getSC());else if (childType === 2) x.push(getRuleset());else if (childType === 3) x.push(getInclude());else if (childType === 4) x.push(getExtend());else if (childType === 5) x.push(getMixin());else if (childType === 6) x.push(getLoop());else if (childType === 7) x.push(getConditionalStatement());else if (childType === 8) x.push(getAtrule());else if (childType === 9) x.push(getDeclaration());else if (childType === 10) x.push(getDeclDelim()); + } + + var token = tokens[startPos]; + return newNode(NodeType.StylesheetType, x, token.ln, token.col); + } + + /** + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkTset(i) { + var l; + if (l = checkVhash(i)) tokens[i].tset_type = 1;else if (l = checkOperator(i)) tokens[i].tset_type = 2;else if (l = checkAny(i)) tokens[i].tset_type = 3;else if (l = checkSC(i)) tokens[i].tset_type = 4;else if (l = checkInterpolation(i)) tokens[i].tset_type = 5; + + return l; + } + + /** + * @returns {Array} + */ + function getTset() { + var tsetType = tokens[pos].tset_type; + + if (tsetType === 1) return getVhash();else if (tsetType === 2) return getOperator();else if (tsetType === 3) return getAny();else if (tsetType === 4) return getSC();else if (tsetType === 5) return getInterpolation(); + } + + /** + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkTsets(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + while (l = checkTset(i)) { + i += l; + } + + tokens[start].tsets_end = i; + return i - start; + } + + /** + * @returns {Array} + */ + function getTsets() { + var x = []; + var t = void 0; + + if (pos >= tokensLength) return x; + + var end = tokens[pos].tsets_end; + while (pos < end) { + t = getTset(); + if (typeof t.content === 'string') x.push(t);else x = x.concat(t); + } + + return x; + } + + /** + * Check if token is an unary (arithmetical) sign (`+` or `-`) + * @param {Number} i Token's index number + * @returns {Number} `1` if token is an unary sign, `0` if not + */ + function checkUnary(i) { + if (i >= tokensLength) { + return 0; + } + + if (tokens[i].type === TokenType.HyphenMinus || tokens[i].type === TokenType.PlusSign) { + return 1; + } + + return 0; + } + + /** + * Get node with an unary (arithmetical) sign (`+` or `-`) + * @returns {Array} `['unary', x]` where `x` is an unary sign + * converted to string. + */ + function getUnary() { + var startPos = pos; + var x = tokens[pos++].value; + + var token = tokens[startPos]; + return newNode(NodeType.OperatorType, x, token.ln, token.col); + } + + /** + * Check if token is a unicode range (single or multiple <urange> nodes) + * @param {number} i Token's index + * @return {number} Unicode range node's length + */ + function checkUnicodeRange(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkUrange(i)) i += l;else return 0; + + while (i < tokensLength) { + var spaceBefore = checkSC(i); + var comma = checkDelim(i + spaceBefore); + if (!comma) break; + + var spaceAfter = checkSC(i + spaceBefore + comma); + if (l = checkUrange(i + spaceBefore + comma + spaceAfter)) { + i += spaceBefore + comma + spaceAfter + l; + } else break; + } + + return i - start; + } + + /** + * Get a unicode range node + * @return {Node} + */ + function getUnicodeRange() { + var type = NodeType.UnicodeRangeType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + while (pos < tokensLength) { + if (checkSC(pos)) content = content.concat(getSC());else if (checkDelim(pos)) content.push(getDelim());else if (checkUrange(pos)) content.push(getUrange());else break; + } + + return newNode(type, content, line, column); + } + + /** + * Check if token is a u-range (part of a unicode-range) + * (1) `U+416` + * (2) `U+400-4ff` + * (3) `U+4??` + * @param {number} i Token's index + * @return {number} Urange node's length + */ + function checkUrange(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + // Check for unicode prefix (u+ or U+) + if (tokens[i].value === 'U' || tokens[i].value === 'u') i += 1;else return 0; + + if (i >= tokensLength) return 0; + + if (tokens[i].value === '+') i += 1;else return 0; + + while (i < tokensLength) { + if (l = checkIdent(i)) i += l;else if (l = checkNumber(i)) i += l;else if (l = checkUnary(i)) i += l;else if (l = _checkUnicodeWildcard(i)) i += l;else break; + } + + tokens[start].urangeEnd = i - 1; + + return i - start; + } + + /** + * Get a u-range node (part of a unicode-range) + * @return {Node} + */ + function getUrange() { + var startPos = pos; + var type = NodeType.UrangeType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + content = joinValues(startPos, tokens[startPos].urangeEnd); + pos = tokens[startPos].urangeEnd + 1; + + return newNode(type, content, line, column); + } + + /** + * Check for unicode wildcard characters `?` + * @param {number} i Token's index + * @return {number} Wildcard length + */ + function _checkUnicodeWildcard(i) { + var start = i; + + if (i >= tokensLength) return 0; + + while (i < tokensLength) { + if (tokens[i].type === TokenType.QuestionMark) i += 1;else break; + } + + tokens[start].uri_raw_end = i; + + return i - start; + } + + /** + * Check if token is part of URI, e.g. `url('/css/styles.css')` + * @param {number} i Token's index number + * @returns {number} Length of URI + */ + function checkUri(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength || tokens[i].value !== 'url') return 0; + + // Skip `url` + i++; + + if (i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis) return 0; + + // Store the opening parenthesis token as we will reference it's `right` + // property to determine when the parentheses close + var leftParenthesis = tokens[i]; + + // Skip `(` + i++; + + // Determine the type of URI + while (i < leftParenthesis.right) { + if (l = checkUri1(i)) { + i += l; + tokens[start].uriType = 1; // Raw based URI (without quotes) + } else if (l = checkUri2(i)) { + i += l; + tokens[start].uriType = 2; // Non-raw based URI (with quotes) + } else return 0; + } + + return i - start; + } + + /** + * Get specific type of URI node + * @return {Node} Specific type of URI node + */ + function getUri() { + var uriType = tokens[pos].uriType; + + if (uriType === 1) return getUri1(); + if (uriType === 2) return getUri2(); + } + + /** + * Check if token type is valid URI character + * @param {number} i Token's index number + * @return {number} Length of raw node + */ + function checkUriRawCharacters(i) { + var start = i; + var l = void 0; + + if (l = checkIdent(i)) i += l;else if (l = checkNumber(i)) i += l;else { + switch (tokens[i].type) { + case TokenType.ExclamationMark: + case TokenType.NumberSign: + case TokenType.DollarSign: + case TokenType.PercentSign: + case TokenType.Ampersand: + case TokenType.Asterisk: + case TokenType.PlusSign: + case TokenType.Comma: + case TokenType.HyphenMinus: + case TokenType.FullStop: + case TokenType.Solidus: + case TokenType.Colon: + case TokenType.Semicolon: + case TokenType.LessThanSign: + case TokenType.EqualsSign: + case TokenType.GreaterThanSign: + case TokenType.QuotationMark: + case TokenType.CommercialAt: + case TokenType.LeftSquareBracket: + case TokenType.RightSquareBracket: + case TokenType.CircumflexAccent: + case TokenType.LowLine: + case TokenType.LeftCurlyBracket: + case TokenType.VerticalLine: + case TokenType.RightCurlyBracket: + case TokenType.Tilde: + i += 1; + break; + + default: + return 0; + } + } + + return i - start; + } + + /** + * Check if content of URI can be contained within a raw node + * @param {number} i Token's index number + * @return {number} Length of raw node + */ + function checkUriRaw(i) { + var start = i; + var l = void 0; + + while (i < tokensLength) { + if (checkInterpolation(i) || checkVariable(i)) break;else if (l = checkUriRawCharacters(i)) i += l;else break; + } + + tokens[start].uri_raw_end = i; + + return i - start; + } + + /** + * Get a raw node + * @return {Node} + */ + function getUriRaw() { + var startPos = pos; + var type = NodeType.RawType; + var token = tokens[startPos]; + var line = token.ln; + var column = token.col; + var content = []; + var l = void 0; + + while (pos < tokens[startPos].uri_raw_end) { + if (checkInterpolation(pos) || checkVariable(pos)) break;else if (l = checkUriRawCharacters(pos)) pos += l;else break; + } + + content = joinValues(startPos, pos - 1); + + return newNode(type, content, line, column); + } + + /** + * Check for a raw (without quotes) URI + * (1) http://foo.com/bar.png + * (2) http://foo.com/#{$bar}.png + * (3) #{$foo}/bar.png + * (4) #{$foo} + * @param {number} i Token's index number + * @return {number} Length of URI node + */ + function checkUri1(i) { + var start = i; + var l = void 0; + + if (l = checkSC(i)) i += l; + + while (i < tokensLength) { + if (l = checkInterpolation(i) || checkUriRaw(i)) i += l;else break; + } + + if (l = checkSC(i)) i += l; + + // Check that we are at the end of the uri + if (i < tokens[start - 1].right) return 0; + + tokens[start].uri_end = i; + + return i - start; + } + + /** + * Get a raw (without quotes) URI + node + * @return {Node} + */ + function getUri1() { + var startPos = pos; + var type = NodeType.UriType; + var token = tokens[startPos]; + var line = token.ln; + var column = token.col; + var content = []; + var end = void 0; + + // Skip `url` and `(` + pos += 2; + + if (checkSC(pos)) content = content.concat(getSC()); + + while (pos < tokens[startPos + 2].uri_end) { + if (checkInterpolation(pos)) content.push(getInterpolation());else if (checkUriRaw(pos)) content.push(getUriRaw());else break; + } + + if (checkSC(pos)) content = content.concat(getSC()); + + // Check that we are at the end of the uri + if (pos < tokens[startPos + 1].right) return 0; + + end = getLastPosition(content, line, column, 1); + + // Skip `)` + pos++; + + return newNode(type, content, line, column, end); + } + + /** + * Check for a non-raw (with quotes) URI + * (1) 'http://foo.com/bar.png' + * (2) 'http://foo.com/'#{$bar}.png + * (3) #{$foo}'/bar.png' + * @param {number} i Token's index number + * @return {number} Length of URI node + */ + function checkUri2(i) { + var start = i; + var l = void 0; + + while (i < tokensLength) { + if (l = checkSC(i)) i += l;else if (l = checkString(i)) i += l;else if (l = checkFunction(i)) i += l;else if (l = checkUnary(i)) i += l;else if (l = checkIdentOrInterpolation(i)) i += l;else if (l = checkVariable(i)) i += l;else break; + } + + tokens[start].uri_end = i; + + return i - start; + } + + /** + * Get a non-raw (with quotes) URI node + * @return {Node} + */ + function getUri2() { + var startPos = pos; + var token = tokens[startPos]; + var line = token.ln; + var column = token.col; + var content = []; + var end = void 0; + + // Skip `url` and `(` + pos += 2; + + while (pos < tokens[startPos + 2].uri_end) { + if (checkSC(pos)) content = content.concat(getSC());else if (checkUnary(pos)) content.push(getUnary());else if (_checkValue(pos)) content.push(_getValue());else break; + } + + end = getLastPosition(content, line, column, 1); + + // Skip `)` + pos++; + + return newNode(NodeType.UriType, content, line, column, end); + } + + /** + * Check if token is part of a value + * @param {Number} i Token's index number + * @returns {Number} Length of the value + */ + function checkValue(i) { + var start = i; + var l = void 0; + var s = void 0; + var _i = void 0; + + while (i < tokensLength) { + if (checkDeclDelim(i)) break; + + s = checkSC(i); + _i = i + s; + + if (l = _checkValue(_i)) i += l + s; + if (!l || checkBlock(i - l)) break; + } + + return i - start; + } + + /** + * @returns {Array} + */ + function getValue() { + var startPos = pos; + var x = []; + var _pos = void 0; + var s = void 0; + + while (pos < tokensLength) { + s = checkSC(pos); + _pos = pos + s; + + if (checkDeclDelim(_pos)) break; + + if (!_checkValue(_pos)) break; + + if (s) x = x.concat(getSC()); + x.push(_getValue()); + + if (checkBlock(_pos)) break; + } + + var token = tokens[startPos]; + return newNode(NodeType.ValueType, x, token.ln, token.col); + } + + /** + * @param {number} i Token's index number + * @returns {number} Length of the value + */ + function checkSingleValue(i) { + var start = i; + var l = void 0; + var s = void 0; + var _i = void 0; + + while (i < tokensLength) { + if (checkDeclDelim(i) || checkDelim(i)) break; + + s = checkSC(i); + _i = i + s; + + if (l = _checkValue(_i)) i += l + s; + if (!l || checkBlock(i - l)) break; + } + + return i - start; + } + + /** + * @returns {Array} + */ + function getSingleValue() { + var startPos = pos; + var x = []; + var _pos = void 0; + var s = void 0; + + while (pos < tokensLength) { + s = checkSC(pos); + _pos = pos + s; + + if (checkDeclDelim(_pos) || checkDelim(_pos)) break; + + if (!_checkValue(_pos)) break; + + if (s) x = x.concat(getSC()); + x.push(_getValue()); + + if (checkBlock(_pos)) break; + } + + var token = tokens[startPos]; + return newNode(NodeType.ValueType, x, token.ln, token.col); + } + + /** + * @param {Number} i Token's index number + * @returns {Number} + */ + function _checkValue(i) { + return checkInterpolation(i) || checkVariable(i) || checkVhash(i) || checkBlock(i) || checkAtkeyword(i) || checkOperator(i) || checkImportant(i) || checkGlobal(i) || checkDefault(i) || checkProgid(i) || checkAny(i) || checkParentSelector(i); + } + + /** + * @returns {Array} + */ + function _getValue() { + if (checkInterpolation(pos)) return getInterpolation();else if (checkVariable(pos)) return getVariable();else if (checkVhash(pos)) return getVhash();else if (checkBlock(pos)) return getBlock();else if (checkAtkeyword(pos)) return getAtkeyword();else if (checkOperator(pos)) return getOperator();else if (checkImportant(pos)) return getImportant();else if (checkGlobal(pos)) return getGlobal();else if (checkDefault(pos)) return getDefault();else if (checkProgid(pos)) return getProgid();else if (checkAny(pos)) return getAny();else if (checkParentSelector(pos)) return getParentSelector(); + } + + /** + * Check if token is part of a variable + * @param {Number} i Token's index number + * @returns {Number} Length of the variable + */ + function checkVariable(i) { + var l; + + if (i >= tokensLength || tokens[i].type !== TokenType.DollarSign) return 0; + + return (l = checkIdent(i + 1)) ? l + 1 : 0; + } + + /** + * Get node with a variable + * @returns {Array} `['variable', ['ident', x]]` where `x` is + * a variable name. + */ + function getVariable() { + var startPos = pos; + var x = []; + + pos++; + + x.push(getIdent()); + + var token = tokens[startPos]; + return newNode(NodeType.VariableType, x, token.ln, token.col); + } + + /** + * Check if token is part of a variables list (e.g. `$values...`). + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkVariablesList(i) { + var d = 0; // Number of dots + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkVariable(i)) i += l;else return 0; + + while (i < tokensLength && tokens[i].type === TokenType.FullStop) { + d++; + i++; + } + + return d === 3 ? l + d : 0; + } + + /** + * Get node with a variables list + * @returns {Array} `['variableslist', ['variable', ['ident', x]]]` where + * `x` is a variable name. + */ + function getVariablesList() { + var startPos = pos; + var x = getVariable(); + var token = tokens[startPos]; + var line = token.ln; + var column = token.col; + + var end = getLastPosition([x], line, column, 3); + pos += 3; + + return newNode(NodeType.VariablesListType, [x], token.ln, token.col, end); + } + + /** + * Check if token is part of a hexadecimal number (e.g. `#fff`) inside + * some value + * @param {Number} i Token's index number + * @returns {Number} + */ + function checkVhash(i) { + var l; + + if (i >= tokensLength || tokens[i].type !== TokenType.NumberSign) return 0; + + return (l = checkNmName2(i + 1)) ? l + 1 : 0; + } + + /** + * Get node with a hexadecimal number (e.g. `#fff`) inside some value + * @returns {Array} `['vhash', x]` where `x` is a hexadecimal number + * converted to string (without `#`, e.g. `'fff'`). + */ + function getVhash() { + var startPos = pos; + var x = void 0; + var token = tokens[startPos]; + var line = token.ln; + var column = token.col; + + pos++; + + x = getNmName2(); + var end = getLastPosition(x, line, column + 1); + return newNode(NodeType.VhashType, x, token.ln, token.col, end); + } + + function checkSelectorsGroup(i) { + if (i >= tokensLength) return 0; + + var start = i; + var l = void 0; + + if (l = checkSelector(i)) i += l;else return 0; + + while (i < tokensLength) { + var sb = checkSC(i); + var c = checkDelim(i + sb); + if (!c) break; + var sa = checkSC(i + sb + c); + if (l = checkSelector(i + sb + c + sa)) i += sb + c + sa + l;else break; + } + + tokens[start].selectorsGroupEnd = i; + return i - start; + } + + function getSelectorsGroup() { + var selectorsGroup = []; + var selectorsGroupEnd = tokens[pos].selectorsGroupEnd; + + selectorsGroup.push(getSelector()); + + while (pos < selectorsGroupEnd) { + selectorsGroup = selectorsGroup.concat(getSC()); + selectorsGroup.push(getDelim()); + selectorsGroup = selectorsGroup.concat(getSC()); + selectorsGroup.push(getSelector()); + } + + return selectorsGroup; + } + + function checkSelector(i) { + var l; + + if (l = checkSelector1(i)) tokens[i].selectorType = 1;else if (l = checkSelector2(i)) tokens[i].selectorType = 2; + + return l; + } + + function getSelector() { + var selectorType = tokens[pos].selectorType; + if (selectorType === 1) return getSelector1();else return getSelector2(); + } + + /** + * Checks for selector which starts with a compound selector. + */ + function checkSelector1(i) { + if (i >= tokensLength) return 0; + + var start = i; + var l = void 0; + + if (l = checkCompoundSelector(i)) i += l;else return 0; + + while (i < tokensLength) { + var s = checkSC(i); + var c = checkCombinator(i + s); + if (!s && !c) break; + if (c) { + i += s + c; + s = checkSC(i); + } + + if (l = checkCompoundSelector(i + s)) i += s + l;else break; + } + + tokens[start].selectorEnd = i; + return i - start; + } + + function getSelector1() { + var type = NodeType.SelectorType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var selectorEnd = token.selectorEnd; + var content = getCompoundSelector(); + + while (pos < selectorEnd) { + if (checkSC(pos)) content = content.concat(getSC());else if (checkCombinator(pos)) content.push(getCombinator());else if (checkCompoundSelector(pos)) content = content.concat(getCompoundSelector()); + } + + return newNode(type, content, line, column); + } + + /** + * Checks for a selector that starts with a combinator. + */ + function checkSelector2(i) { + if (i >= tokensLength) return 0; + + var start = i; + var l = void 0; + + if (l = checkCombinator(i)) i += l;else return 0; + + while (i < tokensLength) { + var sb = checkSC(i); + if (l = checkCompoundSelector(i + sb)) i += sb + l;else break; + + var sa = checkSC(i); + var c = checkCombinator(i + sa); + if (!sa && !c) break; + if (c) { + i += sa + c; + } + } + + tokens[start].selectorEnd = i; + return i - start; + } + + function getSelector2() { + var type = NodeType.SelectorType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var selectorEnd = token.selectorEnd; + var content = [getCombinator()]; + + while (pos < selectorEnd) { + if (checkSC(pos)) content = content.concat(getSC());else if (checkCombinator(pos)) content.push(getCombinator());else if (checkCompoundSelector(pos)) content = content.concat(getCompoundSelector()); + } + + return newNode(type, content, line, column); + } + + function checkCompoundSelector(i) { + var l = void 0; + + if (l = checkCompoundSelector1(i)) { + tokens[i].compoundSelectorType = 1; + } else if (l = checkCompoundSelector2(i)) { + tokens[i].compoundSelectorType = 2; + } + + return l; + } + + function getCompoundSelector() { + var type = tokens[pos].compoundSelectorType; + if (type === 1) return getCompoundSelector1(); + if (type === 2) return getCompoundSelector2(); + } + + /** + * Check for compound selectors that start with either a type selector, + * placeholder or parent selector with extension + * (1) `foo.bar` + * (2) `foo[attr=val]` + * (3) `foo:first-of-type` + * (4) `foo%bar` + * @param {number} i Token's index + * @return {number} Compound selector's length + */ + function checkCompoundSelector1(i) { + if (i >= tokensLength) return 0; + + var start = i; + var l = void 0; + + if (l = checkUniversalSelector(i) || checkTypeSelector(i) || checkPlaceholder(i) || checkParentSelectorWithExtension(i)) i += l;else return 0; + + while (i < tokensLength) { + var _l2 = checkShash(i) || checkClass(i) || checkAttributeSelector(i) || checkPseudo(i) || checkPlaceholder(i); + + if (_l2) i += _l2;else break; + } + + tokens[start].compoundSelectorEnd = i; + + return i - start; + } + + /** + * @return {Array} An array of nodes that make up the compound selector + */ + function getCompoundSelector1() { + var sequence = []; + var compoundSelectorEnd = tokens[pos].compoundSelectorEnd; + + if (checkUniversalSelector(pos)) sequence.push(getUniversalSelector());else if (checkTypeSelector(pos)) sequence.push(getTypeSelector());else if (checkPlaceholder(pos)) sequence.push(getPlaceholder());else if (checkParentSelectorWithExtension(pos)) sequence = sequence.concat(getParentSelectorWithExtension()); + + while (pos < compoundSelectorEnd) { + if (checkShash(pos)) sequence.push(getShash());else if (checkClass(pos)) sequence.push(getClass());else if (checkAttributeSelector(pos)) sequence.push(getAttributeSelector());else if (checkPseudo(pos)) sequence.push(getPseudo());else if (checkPlaceholder(pos)) sequence.push(getPlaceholder());else break; + } + + return sequence; + } + + /** + * Check for all other compound selectors + * (1) `.foo.bar` + * (2) `.foo[attr=val]` + * (3) `.foo:first-of-type` + * (4) `.foo%bar` + * (5) `.foo#{$bar}` + * @param {number} i Token's index + * @return {number} Compound selector's length + */ + function checkCompoundSelector2(i) { + if (i >= tokensLength) return 0; + + var start = i; + + while (i < tokensLength) { + var l = checkShash(i) || checkClass(i) || checkAttributeSelector(i) || checkPseudo(i) || checkPlaceholder(i) || checkInterpolation(i); + + if (l) i += l;else break; + } + + tokens[start].compoundSelectorEnd = i; + + return i - start; + } + + /** + * @return {Array} An array of nodes that make up the compound selector + */ + function getCompoundSelector2() { + var sequence = []; + var compoundSelectorEnd = tokens[pos].compoundSelectorEnd; + + while (pos < compoundSelectorEnd) { + if (checkShash(pos)) sequence.push(getShash());else if (checkClass(pos)) sequence.push(getClass());else if (checkAttributeSelector(pos)) sequence.push(getAttributeSelector());else if (checkPseudo(pos)) sequence.push(getPseudo());else if (checkPlaceholder(pos)) sequence.push(getPlaceholder());else if (checkInterpolation(pos)) sequence.push(getInterpolation());else break; + } + + return sequence; + } + + function checkUniversalSelector(i) { + if (i >= tokensLength) return 0; + + var start = i; + var l = void 0; + + if (l = checkNamePrefix(i)) i += l; + + if (tokens[i].type === TokenType.Asterisk) i++;else return 0; + + return i - start; + } + + function getUniversalSelector() { + var type = NodeType.UniversalSelectorType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + var end = void 0; + + if (checkNamePrefix(pos)) { + content.push(getNamePrefix()); + end = getLastPosition(content, line, column, 1); + } + + pos++; + + return newNode(type, content, line, column, end); + } + + /** + * Check if token is part of a type selector + * @param {number} i Token's index + * @return {number} Type selector's length + */ + function checkTypeSelector(i) { + var start = i; + var l = void 0; + + if (i >= tokensLength) return 0; + + if (l = checkNamePrefix(i)) i += l; + + if (l = checkIdentOrInterpolation(i)) i += l;else return 0; + + return i - start; + } + + /** + * Get type selector node + * @return {Node} + */ + function getTypeSelector() { + var type = NodeType.TypeSelectorType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + if (checkNamePrefix(pos)) content.push(getNamePrefix()); + + content = content.concat(getIdentOrInterpolation()); + + return newNode(type, content, line, column); + } + + function checkAttributeSelector(i) { + var l = void 0; + if (l = checkAttributeSelector1(i)) tokens[i].attributeSelectorType = 1;else if (l = checkAttributeSelector2(i)) tokens[i].attributeSelectorType = 2; + + return l; + } + + function getAttributeSelector() { + var type = tokens[pos].attributeSelectorType; + if (type === 1) return getAttributeSelector1();else return getAttributeSelector2(); + } + + /** + * (1) `[panda=nani]` + * (2) `[panda='nani']` + * (3) `[panda='nani' i]` + * + */ + function checkAttributeSelector1(i) { + var start = i; + + if (tokens[i].type === TokenType.LeftSquareBracket) i++;else return 0; + + var l = void 0; + if (l = checkSC(i)) i += l; + + if (l = checkAttributeName(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkAttributeMatch(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkAttributeValue(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (l = checkAttributeFlags(i)) { + i += l; + if (l = checkSC(i)) i += l; + } + + if (tokens[i].type === TokenType.RightSquareBracket) i++;else return 0; + + return i - start; + } + + function getAttributeSelector1() { + var type = NodeType.AttributeSelectorType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + // Skip `[`. + pos++; + + content = content.concat(getSC()); + content.push(getAttributeName()); + content = content.concat(getSC()); + content.push(getAttributeMatch()); + content = content.concat(getSC()); + content.push(getAttributeValue()); + content = content.concat(getSC()); + + if (checkAttributeFlags(pos)) { + content.push(getAttributeFlags()); + content = content.concat(getSC()); + } + + // Skip `]`. + pos++; + + var end = getLastPosition(content, line, column, 1); + return newNode(type, content, line, column, end); + } + + /** + * (1) `[panda]` + */ + function checkAttributeSelector2(i) { + var start = i; + + if (tokens[i].type === TokenType.LeftSquareBracket) i++;else return 0; + + var l = void 0; + if (l = checkSC(i)) i += l; + + if (l = checkAttributeName(i)) i += l;else return 0; + + if (l = checkSC(i)) i += l; + + if (tokens[i].type === TokenType.RightSquareBracket) i++;else return 0; + + return i - start; + } + + function getAttributeSelector2() { + var type = NodeType.AttributeSelectorType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + // Skip `[`. + pos++; + + content = content.concat(getSC()); + content.push(getAttributeName()); + content = content.concat(getSC()); + + // Skip `]`. + pos++; + + var end = getLastPosition(content, line, column, 1); + return newNode(type, content, line, column, end); + } + + function checkAttributeName(i) { + var start = i; + var l = void 0; + + if (l = checkNamePrefix(i)) i += l; + + if (l = checkIdentOrInterpolation(i)) i += l;else return 0; + + return i - start; + } + + function getAttributeName() { + var type = NodeType.AttributeNameType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + if (checkNamePrefix(pos)) content.push(getNamePrefix()); + content = content.concat(getIdentOrInterpolation()); + + return newNode(type, content, line, column); + } + + function checkAttributeMatch(i) { + var l = void 0; + if (l = checkAttributeMatch1(i)) tokens[i].attributeMatchType = 1;else if (l = checkAttributeMatch2(i)) tokens[i].attributeMatchType = 2; + + return l; + } + + function getAttributeMatch() { + var type = tokens[pos].attributeMatchType; + if (type === 1) return getAttributeMatch1();else return getAttributeMatch2(); + } + + function checkAttributeMatch1(i) { + var start = i; + + var type = tokens[i].type; + if (type === TokenType.Tilde || type === TokenType.VerticalLine || type === TokenType.CircumflexAccent || type === TokenType.DollarSign || type === TokenType.Asterisk) i++;else return 0; + + if (tokens[i].type === TokenType.EqualsSign) i++;else return 0; + + return i - start; + } + + function getAttributeMatch1() { + var type = NodeType.AttributeMatchType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = tokens[pos].value + tokens[pos + 1].value; + pos += 2; + + return newNode(type, content, line, column); + } + + function checkAttributeMatch2(i) { + if (tokens[i].type === TokenType.EqualsSign) return 1;else return 0; + } + + function getAttributeMatch2() { + var type = NodeType.AttributeMatchType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = '='; + + pos++; + return newNode(type, content, line, column); + } + + function checkAttributeValue(i) { + return checkString(i) || checkIdentOrInterpolation(i); + } + + function getAttributeValue() { + var type = NodeType.AttributeValueType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + if (checkString(pos)) content.push(getString());else content = content.concat(getIdentOrInterpolation()); + + return newNode(type, content, line, column); + } + + function checkAttributeFlags(i) { + return checkIdentOrInterpolation(i); + } + + function getAttributeFlags() { + var type = NodeType.AttributeFlagsType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = getIdentOrInterpolation(); + + return newNode(type, content, line, column); + } + + function checkNamePrefix(i) { + if (i >= tokensLength) return 0; + + var l = void 0; + if (l = checkNamePrefix1(i)) tokens[i].namePrefixType = 1;else if (l = checkNamePrefix2(i)) tokens[i].namePrefixType = 2; + + return l; + } + + function getNamePrefix() { + var type = tokens[pos].namePrefixType; + if (type === 1) return getNamePrefix1();else return getNamePrefix2(); + } + + /** + * (1) `panda|` + * (2) `panda<comment>|` + */ + function checkNamePrefix1(i) { + var start = i; + var l = void 0; + + if (l = checkNamespacePrefix(i)) i += l;else return 0; + + if (l = checkCommentML(i)) i += l; + + if (l = checkNamespaceSeparator(i)) i += l;else return 0; + + return i - start; + } + + function getNamePrefix1() { + var type = NodeType.NamePrefixType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + content.push(getNamespacePrefix()); + + if (checkCommentML(pos)) content.push(getCommentML()); + + content.push(getNamespaceSeparator()); + + return newNode(type, content, line, column); + } + + /** + * (1) `|` + */ + function checkNamePrefix2(i) { + return checkNamespaceSeparator(i); + } + + function getNamePrefix2() { + var type = NodeType.NamePrefixType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = [getNamespaceSeparator()]; + + return newNode(type, content, line, column); + } + + /** + * (1) `*` + * (2) `panda` + */ + function checkNamespacePrefix(i) { + if (i >= tokensLength) return 0; + + var l = void 0; + + if (tokens[i].type === TokenType.Asterisk) return 1;else if (l = checkIdentOrInterpolation(i)) return l;else return 0; + } + + function getNamespacePrefix() { + var type = NodeType.NamespacePrefixType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = []; + + if (token.type === TokenType.Asterisk) { + var asteriskNode = newNode(NodeType.IdentType, '*', token.ln, token.col); + content.push(asteriskNode); + pos++; + } else if (checkIdentOrInterpolation(pos)) content = content.concat(getIdentOrInterpolation()); + + return newNode(type, content, line, column); + } + + /** + * (1) `|` + */ + function checkNamespaceSeparator(i) { + if (i >= tokensLength) return 0; + + if (tokens[i].type !== TokenType.VerticalLine) return 0; + + // Return false if `|=` - [attr|=value] + if (tokens[i + 1] && tokens[i + 1].type === TokenType.EqualsSign) return 0; + + return 1; + } + + function getNamespaceSeparator() { + var type = NodeType.NamespaceSeparatorType; + var token = tokens[pos]; + var line = token.ln; + var column = token.col; + var content = '|'; + + pos++; + return newNode(type, content, line, column); + } + + module.exports = function (_tokens, context) { + tokens = _tokens; + tokensLength = tokens.length; + pos = 0; + + return contexts[context](); + }; + +/***/ }, +/* 20 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + module.exports = function (css, tabSize) { + var TokenType = __webpack_require__(13); + + var tokens = []; + var urlMode = false; + var c = void 0; // Current character + var cn = void 0; // Next character var pos = 0; var tn = 0; var ln = 1; @@ -1896,7 +9952,8 @@ '{': TokenType.LeftCurlyBracket, '|': TokenType.VerticalLine, '}': TokenType.RightCurlyBracket, - '~': TokenType.Tilde + '~': TokenType.Tilde, + '`': TokenType.Backtick }; /** @@ -1985,9 +10042,9 @@ var start = pos; // Skip all opening slashes: - while (css.charAt(pos) === '/') pos++; - - // Read the string until we meet a punctuation mark: + while (css.charAt(pos) === '/') { + pos++; + } // Read the string until we meet a punctuation mark: for (; pos < css.length; pos++) { // Skip all '\': if (css.charAt(pos) === '\\') pos++;else if (css.charAt(pos) in Punctuation) break; @@ -2133,20 +10190,18 @@ pushToken(TokenType.Newline, '\r\n', col); pos++; // If CRLF skip the next character and push crlf token } else if (c === '\n') { - // If just a LF newline and not part of CRLF newline we can just - // push punctuation as usual - pushToken(Punctuation[c], c, col); - } + // If just a LF newline and not part of CRLF newline we can just + // push punctuation as usual + pushToken(Punctuation[c], c, col); + } ln++; // Go to next line col = 0; // Reset the column count } else if (c !== '\r' && c !== '\n') { - // Handle all other punctuation and add to list of tokens - pushToken(Punctuation[c], c, col); - } // Go to next line + // Handle all other punctuation and add to list of tokens + pushToken(Punctuation[c], c, col); + } // Go to next line if (c === ')') urlMode = false; // Exit url mode - if (c === '{') blockMode++; // Enter a block - if (c === '}') blockMode--; // Exit a block else if (c === '\t' && tabSize > 1) col += tabSize - 1; } @@ -2168,13 +10223,13 @@ }; /***/ }, -/* 16 */ +/* 21 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var Node = __webpack_require__(1); - var NodeTypes = __webpack_require__(14); + var NodeTypes = __webpack_require__(15); module.exports = function () { return new Node({
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/AppManifestView.js b/third_party/WebKit/Source/devtools/front_end/resources/AppManifestView.js index 78f8530..a8ae577c 100644 --- a/third_party/WebKit/Source/devtools/front_end/resources/AppManifestView.js +++ b/third_party/WebKit/Source/devtools/front_end/resources/AppManifestView.js
@@ -10,8 +10,14 @@ super(true); this.registerRequiredCSS('resources/appManifestView.css'); + this._emptyView = new UI.EmptyWidget(Common.UIString('No web app manifest')); + + this._emptyView.show(this.contentElement); + this._emptyView.hideWidget(); + this._reportView = new UI.ReportView(Common.UIString('App Manifest')); this._reportView.show(this.contentElement); + this._reportView.hideWidget(); this._errorsSection = this._reportView.appendSection(Common.UIString('Errors and warnings')); this._identitySection = this._reportView.appendSection(Common.UIString('Identity')); @@ -81,6 +87,14 @@ * @param {!Array<!Protocol.Page.AppManifestError>} errors */ _renderManifest(url, data, errors) { + if (!data && !errors.length) { + this._emptyView.showWidget(); + this._reportView.hideWidget(); + return; + } + this._emptyView.hideWidget(); + this._reportView.showWidget(); + this._reportView.setURL(Components.Linkifier.linkifyURL(url)); this._errorsSection.clearContent(); this._errorsSection.element.classList.toggle('hidden', !errors.length);
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/StorageItemsView.js b/third_party/WebKit/Source/devtools/front_end/resources/StorageItemsView.js index a404165..9692ac0 100644 --- a/third_party/WebKit/Source/devtools/front_end/resources/StorageItemsView.js +++ b/third_party/WebKit/Source/devtools/front_end/resources/StorageItemsView.js
@@ -12,30 +12,21 @@ /** @type {?RegExp} */ this._filterRegex = null; - this._filterBar = new UI.FilterBar(filterName, true); - this._textFilterUI = new UI.TextFilterUI(false); - this._textFilterUI.addEventListener(UI.FilterUI.Events.FilterChanged, this._filterChanged, this); - this._filterBar.addFilter(this._textFilterUI); - this._deleteAllButton = this._addButton(Common.UIString('Clear All'), 'largeicon-clear', this.deleteAllItems); this._deleteSelectedButton = this._addButton(Common.UIString('Delete Selected'), 'largeicon-delete', this.deleteSelectedItem); this._refreshButton = this._addButton(Common.UIString('Refresh'), 'largeicon-refresh', this.refreshItems); - this._filterButton = this._filterBar.filterButton(); this._mainToolbar = new UI.Toolbar('top-resources-toolbar', this.element); - var toolbarItems = [ - this._refreshButton, this._deleteAllButton, this._deleteSelectedButton, new UI.ToolbarSeparator(), - this._filterButton - ]; + this._filterItem = new UI.ToolbarInput(Common.UIString('Filter'), 0.4, undefined, true); + this._filterItem.addEventListener(UI.ToolbarInput.Event.TextChanged, this._filterChanged, this); - this.element.addEventListener('contextmenu', this._showContextMenu.bind(this), true); - + var toolbarItems = [this._refreshButton, this._deleteAllButton, this._deleteSelectedButton, this._filterItem]; for (var item of toolbarItems) this._mainToolbar.appendToolbarItem(item); - this._filterBar.show(this.element); + this.element.addEventListener('contextmenu', this._showContextMenu.bind(this), true); } /** @@ -59,12 +50,11 @@ contextMenu.show(); } - /** * @param {!Common.Event} event */ _filterChanged(event) { - var text = this._textFilterUI.value(); + var text = /** @type {?string} */ (event.data); this._filterRegex = text ? new RegExp(text.escapeForRegExp(), 'i') : null; this.refreshItems(); } @@ -89,13 +79,6 @@ } /** - * @override - */ - willHide() { - this.setCanDeleteSelected(false); - } - - /** * @param {boolean} enabled * @protected */ @@ -124,7 +107,7 @@ * @protected */ setCanFilter(enabled) { - this._filterButton.setEnabled(enabled); + this._filterItem.setEnabled(enabled); } deleteAllItems() {
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/EventListenerBreakpointsSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/sources/EventListenerBreakpointsSidebarPane.js index 75f7496e..b39685ff 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/EventListenerBreakpointsSidebarPane.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/EventListenerBreakpointsSidebarPane.js
@@ -24,6 +24,8 @@ // this._createCategory(Common.UIString("Drag"), ["drag", "drop", "dragstart", "dragend", "dragenter", "dragleave", "dragover"]); this._createCategory( Common.UIString('Animation'), ['requestAnimationFrame', 'cancelAnimationFrame', 'animationFrameFired'], true); + this._createCategory(Common.UIString('Canvas'), ['canvasContextCreated', 'webglErrorFired', 'webglWarningFired'], + true); this._createCategory( Common.UIString('Clipboard'), ['copy', 'cut', 'paste', 'beforecopy', 'beforecut', 'beforepaste']); this._createCategory( @@ -60,7 +62,6 @@ this._createCategory(Common.UIString('Script'), ['scriptFirstStatement', 'scriptBlockedByCSP'], true); this._createCategory(Common.UIString('Timer'), ['setTimer', 'clearTimer', 'timerFired'], true); this._createCategory(Common.UIString('Touch'), ['touchstart', 'touchmove', 'touchend', 'touchcancel']); - this._createCategory(Common.UIString('WebGL'), ['webglErrorFired', 'webglWarningFired'], true); this._createCategory(Common.UIString('Window'), ['close'], true); this._createCategory( Common.UIString('XHR'), @@ -92,6 +93,7 @@ 'instrumentation:webglErrorFired': Common.UIString('WebGL Error Fired'), 'instrumentation:webglWarningFired': Common.UIString('WebGL Warning Fired'), 'instrumentation:setInnerHTML': Common.UIString('Set innerHTML'), + 'instrumentation:canvasContextCreated': Common.UIString('Create canvas context'), }; } if (auxData) {
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/EventsTimelineTreeView.js b/third_party/WebKit/Source/devtools/front_end/timeline/EventsTimelineTreeView.js index baa94a9..8ae6fb358 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/EventsTimelineTreeView.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/EventsTimelineTreeView.js
@@ -40,7 +40,7 @@ * @return {!TimelineModel.TimelineProfileTree.Node} */ _buildTree() { - this._currentTree = this.buildTopDownTree(); + this._currentTree = this.buildTopDownTree(true, null); return this._currentTree; }
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js index c97b922..54b12a7f 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js
@@ -177,12 +177,13 @@ /** * @protected - * @param {function(!SDK.TracingModel.Event):(string|symbol)=} eventIdCallback + * @param {boolean} doNotAggregate + * @param {?function(!SDK.TracingModel.Event):string} groupIdCallback * @return {!TimelineModel.TimelineProfileTree.Node} */ - buildTopDownTree(eventIdCallback) { - return TimelineModel.TimelineProfileTree.buildTopDown( - this._model.mainThreadEvents(), this._filters, this._startTime, this._endTime, eventIdCallback); + buildTopDownTree(doNotAggregate, groupIdCallback) { + return new TimelineModel.TimelineProfileTree.TopDownRootNode( + this._model.mainThreadEvents(), this._filters, this._startTime, this._endTime, doNotAggregate, groupIdCallback); } /** @@ -634,7 +635,7 @@ /** * @param {!Timeline.AggregatedTimelineTreeView.GroupBy} groupBy - * @return {function(!SDK.TracingModel.Event):(string|symbol)} + * @return {?function(!SDK.TracingModel.Event):string} */ _groupingFunction(groupBy) { /** @@ -671,7 +672,7 @@ switch (groupBy) { case Timeline.AggregatedTimelineTreeView.GroupBy.None: - return () => Symbol('uniqueGroupId'); + return null; case Timeline.AggregatedTimelineTreeView.GroupBy.EventName: return event => Timeline.TimelineUIUtils.eventStyle(event).title; case Timeline.AggregatedTimelineTreeView.GroupBy.Category: @@ -686,7 +687,7 @@ return event => TimelineModel.TimelineData.forEvent(event).frameId; default: console.assert(false, `Unexpected aggregation setting: ${groupBy}`); - return () => Symbol('uniqueGroupId'); + return null; } } /** @@ -757,10 +758,7 @@ */ _buildTree() { var grouping = this._groupBySetting.get(); - var topDown = this.buildTopDownTree(this._groupingFunction(grouping)); - if (grouping === Timeline.AggregatedTimelineTreeView.GroupBy.None) - return topDown; - return new TimelineModel.TimelineAggregator().performGrouping(topDown); + return this.buildTopDownTree(false, this._groupingFunction(grouping)); } };
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineJSProfile.js b/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineJSProfile.js index 7749bafb..3769b45 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineJSProfile.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineJSProfile.js
@@ -53,7 +53,9 @@ * @return {boolean} */ function equalFrames(frame1, frame2) { - return frame1.scriptId === frame2.scriptId && frame1.functionName === frame2.functionName; + return frame1.scriptId === frame2.scriptId && + frame1.functionName === frame2.functionName && + frame1.lineNumber === frame2.lineNumber; } /**
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineProfileTree.js b/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineProfileTree.js index 533f064..643be95 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineProfileTree.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineProfileTree.js
@@ -55,11 +55,15 @@ /** * @param {string} id * @param {?SDK.TracingModel.Event} event + * @param {?TimelineModel.TimelineProfileTree.TopDownNode} parent */ - constructor(id, event) { + constructor(id, event, parent) { super(id, event); - /** @type {!Map<string, !TimelineModel.TimelineProfileTree.Node>} */ - this._children = new Map(); + /** @type {?TimelineModel.TimelineProfileTree.TopDownRootNode} */ + this._root = parent && parent._root; + this._hasChildren = false; + this._children = null; + this.parent = parent; } /** @@ -67,7 +71,7 @@ * @return {boolean} */ hasChildren() { - return !!this._children.size; + return this._hasChildren; } /** @@ -75,73 +79,177 @@ * @return {!Map<string, !TimelineModel.TimelineProfileTree.Node>} */ children() { - return this._children; + return this._children || this._buildChildren(); + } + + /** + * @return {!Map<string, !TimelineModel.TimelineProfileTree.Node>} + */ + _buildChildren() { + /** @type {!Array<!TimelineModel.TimelineProfileTree.TopDownNode>} */ + var path = []; + for (var node = this; node.parent; node = node.parent) + path.push(/** @type {!TimelineModel.TimelineProfileTree.TopDownNode} */ (node)); + path.reverse(); + /** @type {!Map<string, !TimelineModel.TimelineProfileTree.Node>} */ + var children = new Map(); + var self = this; + var root = this._root; + var startTime = root._startTime; + var endTime = root._endTime; + var instantEventCallback = root._doNotAggregate ? onInstantEvent : undefined; + var eventIdCallback = root._doNotAggregate ? undefined : TimelineModel.TimelineProfileTree._eventId; + var eventGroupIdCallback = root._eventGroupIdCallback; + var depth = 0; + var matchedDepth = 0; + var currentDirectChild = null; + TimelineModel.TimelineModel.forEachEvent( + root._events, onStartEvent, onEndEvent, instantEventCallback, startTime, endTime, root._filter); + + /** + * @param {!SDK.TracingModel.Event} e + */ + function onStartEvent(e) { + ++depth; + if (depth > path.length + 2) + return; + if (!matchPath(e)) + return; + var duration = Math.min(endTime, e.endTime) - Math.max(startTime, e.startTime); + if (duration < 0) + console.error('Negative event duration'); + processEvent(e, duration); + } + + /** + * @param {!SDK.TracingModel.Event} e + */ + function onInstantEvent(e) { + if (matchedDepth === path.length && matchedDepth === depth) + processEvent(e, 0); + } + + /** + * @param {!SDK.TracingModel.Event} e + * @param {number} duration + */ + function processEvent(e, duration) { + if (depth === path.length + 2) { + currentDirectChild._hasChildren = true; + currentDirectChild.selfTime -= duration; + return; + } + var id; + var groupId = ''; + if (!eventIdCallback) { + id = Symbol('uniqueId'); + } else { + id = eventIdCallback(e); + groupId = eventGroupIdCallback ? eventGroupIdCallback(e) : ''; + if (groupId) + id += '/' + groupId; + } + var node = children.get(id); + if (!node) { + node = new TimelineModel.TimelineProfileTree.TopDownNode(id, e, self); + node._groupId = groupId; + children.set(id, node); + } + node.selfTime += duration; + node.totalTime += duration; + currentDirectChild = node; + } + + /** + * @param {!SDK.TracingModel.Event} e + * @return {boolean} + */ + function matchPath(e) { + if (matchedDepth === path.length) + return true; + if (matchedDepth !== depth - 1) + return false; + if (!e.endTime) + return false; + if (!eventIdCallback) { + if (e === path[matchedDepth].event) + ++matchedDepth; + return false; + } + var id = eventIdCallback(e); + var groupId = eventGroupIdCallback ? eventGroupIdCallback(e) : ''; + if (groupId) + id += '/' + groupId; + if (id === path[matchedDepth].id) + ++matchedDepth; + return false; + } + + /** + * @param {!SDK.TracingModel.Event} e + */ + function onEndEvent(e) { + --depth; + if (matchedDepth > depth) + matchedDepth = depth; + } + + this._children = children; + return children; } }; -/** - * @param {!Array<!SDK.TracingModel.Event>} events - * @param {!Array<!TimelineModel.TimelineModelFilter>} filters - * @param {number} startTime - * @param {number} endTime - * @param {function(!SDK.TracingModel.Event):string=} eventGroupIdCallback - * @return {!TimelineModel.TimelineProfileTree.Node} - */ -TimelineModel.TimelineProfileTree.buildTopDown = function(events, filters, startTime, endTime, eventGroupIdCallback) { - // Temporarily deposit a big enough value that exceeds the max recording time. - var /** @const */ initialTime = 1e7; - var root = new TimelineModel.TimelineProfileTree.TopDownNode('', null); - root.totalTime = initialTime; - root.selfTime = initialTime; - var parent = root; - +TimelineModel.TimelineProfileTree.TopDownRootNode = class extends TimelineModel.TimelineProfileTree.TopDownNode { /** - * @param {!SDK.TracingModel.Event} e + * @param {!Array<!SDK.TracingModel.Event>} events + * @param {!Array<!TimelineModel.TimelineModelFilter>} filters + * @param {number} startTime + * @param {number} endTime + * @param {boolean=} doNotAggregate + * @param {?function(!SDK.TracingModel.Event):string=} eventGroupIdCallback */ - function onStartEvent(e) { - if (!TimelineModel.TimelineModel.isVisible(filters, e)) - return; - var time = e.endTime ? Math.min(endTime, e.endTime) - Math.max(startTime, e.startTime) : 0; - var groupId = eventGroupIdCallback ? eventGroupIdCallback(e) : Symbol('uniqueGroupId'); - var id = eventGroupIdCallback ? TimelineModel.TimelineProfileTree._eventId(e) : Symbol('uniqueEventId'); - if (typeof groupId === 'string' && typeof id === 'string') - id += '/' + groupId; - var node = parent.children().get(id); - if (node) { - node.selfTime += time; - node.totalTime += time; - } else { - node = new TimelineModel.TimelineProfileTree.TopDownNode(id, e); - node.totalTime = time; - node.selfTime = time; - node.parent = parent; - node._groupId = groupId; - parent.children().set(id, node); - } - parent.selfTime -= time; - if (parent.selfTime < 0) { - console.error('Error: Negative self of ' + parent.selfTime, e); - parent.selfTime = 0; - } - if (e.endTime) - parent = node; + constructor(events, filters, startTime, endTime, doNotAggregate, eventGroupIdCallback) { + super('', null, null); + this._root = this; + this._events = events; + this._filter = e => TimelineModel.TimelineModel.isVisible(filters, e); + this._startTime = startTime; + this._endTime = endTime; + this._eventGroupIdCallback = eventGroupIdCallback; + this._doNotAggregate = doNotAggregate; + this.totalTime = endTime - startTime; + this.selfTime = this.totalTime; } /** - * @param {!SDK.TracingModel.Event} e + * @override + * @return {!Map<string, !TimelineModel.TimelineProfileTree.Node>} */ - function onEndEvent(e) { - if (!TimelineModel.TimelineModel.isVisible(filters, e)) - return; - parent = parent.parent; + children() { + return this._children || this._grouppedTopNodes(); } - var instantEventCallback = - eventGroupIdCallback ? undefined : onStartEvent; // Ignore instant events when aggregating. - TimelineModel.TimelineModel.forEachEvent(events, onStartEvent, onEndEvent, instantEventCallback, startTime, endTime); - root.totalTime -= root.selfTime; - root.selfTime = 0; - return root; + /** + * @return {!Map<string, !TimelineModel.TimelineProfileTree.Node>} + */ + _grouppedTopNodes() { + var flatNodes = super.children(); + if (!this._eventGroupIdCallback) + return flatNodes; + var groupNodes = new Map(); + for (var node of flatNodes.values()) { + var groupId = this._eventGroupIdCallback(/** @type {!SDK.TracingModel.Event} */ (node.event)); + var groupNode = groupNodes.get(groupId); + if (!groupNode) { + groupNode = new TimelineModel.TimelineProfileTree.GroupNode( + groupId, /** @type {!SDK.TracingModel.Event} */ (node.event)); + groupNodes.set(groupId, groupNode); + } + groupNode.addChild(node, node.selfTime, node.totalTime); + } + this._children = groupNodes; + return groupNodes; + } }; TimelineModel.TimelineProfileTree.BottomUpTreeRootNode = class extends TimelineModel.TimelineProfileTree.Node { @@ -150,7 +258,7 @@ * @param {!Array<!TimelineModel.TimelineModelFilter>} filters * @param {number} startTime * @param {number} endTime - * @param {function(!SDK.TracingModel.Event):string=} eventGroupIdCallback + * @param {?function(!SDK.TracingModel.Event):string} eventGroupIdCallback */ constructor(events, filters, startTime, endTime, eventGroupIdCallback) { super('', null); @@ -240,26 +348,25 @@ */ _grouppedTopNodes() { var flatNodes = this._ungrouppedTopNodes(); + if (!this._eventGroupIdCallback) + return flatNodes; var groupNodes = new Map(); for (var node of flatNodes.values()) { var groupId = this._eventGroupIdCallback(/** @type {!SDK.TracingModel.Event} */ (node.event)); - if (typeof groupId !== 'string') - return flatNodes; var groupNode = groupNodes.get(groupId); if (!groupNode) { - groupNode = new TimelineModel.TimelineProfileTree.BottomUpTreeGroupNode( + groupNode = new TimelineModel.TimelineProfileTree.GroupNode( groupId, /** @type {!SDK.TracingModel.Event} */ (node.event)); - groupNode.parent = this; groupNodes.set(groupId, groupNode); } - groupNode.addChild(node); + groupNode.addChild(node, node.selfTime, node.selfTime); node.parent = groupNode; } return groupNodes; } }; -TimelineModel.TimelineProfileTree.BottomUpTreeGroupNode = class extends TimelineModel.TimelineProfileTree.Node { +TimelineModel.TimelineProfileTree.GroupNode = class extends TimelineModel.TimelineProfileTree.Node { /** * @param {string} id * @param {!SDK.TracingModel.Event} event @@ -272,11 +379,13 @@ /** * @param {!TimelineModel.TimelineProfileTree.BottomUpTreeNode} child + * @param {number} selfTime + * @param {number} totalTime */ - addChild(child) { + addChild(child, selfTime, totalTime) { this._children.set(child.id, child); - this.selfTime += child.selfTime; - this.totalTime += child.selfTime; + this.selfTime += selfTime; + this.totalTime += totalTime; } /** @@ -432,54 +541,3 @@ functionName; return `f:${name}@${location}`; }; - -/** - * @unrestricted - */ -TimelineModel.TimelineAggregator = class { - constructor() { - /** @type {!Map<string, !TimelineModel.TimelineProfileTree.TopDownNode>} */ - this._groupNodes = new Map(); - } - - /** - * @param {!TimelineModel.TimelineProfileTree.Node} root - * @return {!TimelineModel.TimelineProfileTree.Node} - */ - performGrouping(root) { - for (var node of root.children().values()) { - var groupNode = this.groupNodeForId(node._groupId, /** @type {!SDK.TracingModel.Event} */ (node.event)); - groupNode.parent = root; - groupNode.selfTime += node.selfTime; - groupNode.totalTime += node.totalTime; - groupNode.children().set(node.id, node); - node.parent = root; - } - root._children = this._groupNodes; - return root; - } - - /** - * @param {string} groupId - * @param {!SDK.TracingModel.Event} event - * @return {!TimelineModel.TimelineProfileTree.Node} - */ - groupNodeForId(groupId, event) { - var node = this._groupNodes.get(groupId); - return node || this._buildGroupNode(groupId, event); - } - - /** - * @param {string} id - * @param {!SDK.TracingModel.Event} event - * @return {!TimelineModel.TimelineProfileTree.Node} - */ - _buildGroupNode(id, event) { - var groupNode = new TimelineModel.TimelineProfileTree.TopDownNode(id, event); - groupNode.selfTime = 0; - groupNode.totalTime = 0; - groupNode._isGroupNode = true; - this._groupNodes.set(id, groupNode); - return groupNode; - } -};
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/FilterBar.js b/third_party/WebKit/Source/devtools/front_end/ui/FilterBar.js index 04f5744..a1e87aaba 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/FilterBar.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/FilterBar.js
@@ -189,10 +189,8 @@ this._proxyElement = this._prompt.attach(this._filterInputElement); this._prompt.setPlaceholder(Common.UIString('Filter')); - this._proxyElement.addEventListener('input', this._valueChanged.bind(this), false); this._proxyElement.addEventListener('keydown', this._onInputKeyDown.bind(this), false); - this._prompt.addEventListener(UI.TextPrompt.Events.ItemAccepted, this._valueChanged.bind(this)); - this._prompt.addEventListener(UI.TextPrompt.Events.ItemApplied, this._valueChanged.bind(this)); + this._prompt.on(UI.TextPrompt.TextChangedEvent, this._valueChanged.bind(this)); /** @type {?function(string, string, boolean=):!Promise<!UI.SuggestBox.Suggestions>} */ this._suggestionProvider = null;
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/InspectorView.js b/third_party/WebKit/Source/devtools/front_end/ui/InspectorView.js index d1f4732d..09b1242 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/InspectorView.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/InspectorView.js
@@ -231,12 +231,12 @@ */ _keyDown(event) { var keyboardEvent = /** @type {!KeyboardEvent} */ (event); - if (!UI.KeyboardShortcut.eventHasCtrlOrMeta(keyboardEvent)) + if (!UI.KeyboardShortcut.eventHasCtrlOrMeta(keyboardEvent) || event.altKey || event.shiftKey) return; // Ctrl/Cmd + 1-9 should show corresponding panel. var panelShortcutEnabled = Common.moduleSetting('shortcutPanelSwitch').get(); - if (panelShortcutEnabled && !event.shiftKey && !event.altKey) { + if (panelShortcutEnabled) { var panelIndex = -1; if (event.keyCode > 0x30 && event.keyCode < 0x3A) panelIndex = event.keyCode - 0x31;
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js b/third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js index 375e45a..06160f5 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js
@@ -307,6 +307,7 @@ this._queryRange.endColumn += text.length - this._previousText.length; this._refreshGhostText(); this._previousText = text; + this.emit(new UI.TextPrompt.TextChangedEvent()); this.autoCompleteSoon(); } @@ -334,7 +335,7 @@ this._refreshGhostText(); if (beforeText !== this.textWithCurrentSuggestion()) - this.dispatchEventToListeners(UI.TextPrompt.Events.ItemApplied); + this.emit(new UI.TextPrompt.TextChangedEvent()); } _refreshGhostText() { @@ -508,7 +509,7 @@ this._currentSuggestion = suggestion; this._refreshGhostText(); if (isIntermediateSuggestion) - this.dispatchEventToListeners(UI.TextPrompt.Events.ItemApplied); + this.emit(new UI.TextPrompt.TextChangedEvent()); } /** @@ -531,7 +532,7 @@ this._queryRange.startColumn + this._currentSuggestion.length); this.clearAutocomplete(); - this.dispatchEventToListeners(UI.TextPrompt.Events.ItemAccepted); + this.emit(new UI.TextPrompt.TextChangedEvent()); return true; } @@ -638,8 +639,5 @@ UI.TextPrompt.DefaultAutocompletionTimeout = 250; -/** @enum {symbol} */ -UI.TextPrompt.Events = { - ItemApplied: Symbol('text-prompt-item-applied'), - ItemAccepted: Symbol('text-prompt-item-accepted') -}; +/** @implements {Common.Emittable} */ +UI.TextPrompt.TextChangedEvent = class {};
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js b/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js index 08ef50bb..e94ecae 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
@@ -552,39 +552,73 @@ */ UI.ToolbarInput = class extends UI.ToolbarItem { /** - * @param {string=} placeholder + * @param {string} placeholder * @param {number=} growFactor * @param {number=} shrinkFactor + * @param {boolean=} isSearchField */ - constructor(placeholder, growFactor, shrinkFactor) { - super(createElementWithClass('input', 'toolbar-item')); - this.element.addEventListener('input', this._onChangeCallback.bind(this), false); + constructor(placeholder, growFactor, shrinkFactor, isSearchField) { + super(createElementWithClass('div', 'toolbar-input')); + + this.input = this.element.createChild('input'); + this.input.addEventListener('focus', () => this.element.classList.add('focused')); + this.input.addEventListener('blur', () => this.element.classList.remove('focused')); + this.input.addEventListener('input', () => this._onChangeCallback(), false); + this._isSearchField = !!isSearchField; if (growFactor) this.element.style.flexGrow = growFactor; if (shrinkFactor) this.element.style.flexShrink = shrinkFactor; if (placeholder) - this.element.setAttribute('placeholder', placeholder); - this._value = ''; + this.input.setAttribute('placeholder', placeholder); + + if (isSearchField) + this._setupSearchControls(); + } + + _setupSearchControls() { + var clearButton = this.element.createChild('div', 'toolbar-input-clear-button'); + clearButton.appendChild(UI.Icon.create('smallicon-clear-input', 'search-cancel-button')); + clearButton.addEventListener('click', () => this._internalSetValue('', true)); + this.input.addEventListener('keydown', event => this._onKeydownCallback(event)); } /** * @param {string} value */ setValue(value) { - this._value = value; - this.element.value = value; + this._internalSetValue(value, false); + } + + /** + * @param {string} value + * @param {boolean} notify + */ + _internalSetValue(value, notify) { + this.input.value = value; + if (notify) + this._onChangeCallback(); } /** * @return {string} */ value() { - return this.element.value; + return this.input.value; + } + + /** + * @param {!Event} event + */ + _onKeydownCallback(event) { + if (this.isSearchField || !isEscKey(event) || !this.input.value) + return; + this._internalSetValue('', true); + event.consume(true); } _onChangeCallback() { - this.dispatchEventToListeners(UI.ToolbarInput.Event.TextChanged, this.element.value); + this.dispatchEventToListeners(UI.ToolbarInput.Event.TextChanged, this.input.value); } };
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css b/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css index 6223cbf..948e3ffc 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css +++ b/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css
@@ -200,7 +200,7 @@ /* Input */ -input.toolbar-item { +.toolbar-input { width: 120px; height: 20px; padding: 3px; @@ -209,11 +209,27 @@ border: solid 1px #d8d8d8; } -input.toolbar-item:focus, -input.toolbar-item.hover { +.toolbar-input.focused, +.toolbar-input.hover { border: solid 1px rgb(202, 202, 202); } +.toolbar-input > input { + border: none; + flex-grow: 1; +} + +.toolbar-input-clear-button { + opacity: 0.7; + flex-basis: 13px; + flex-shrink: 0; + height: 13px; +} + +.toolbar-input-clear-button:hover { + opacity: 1; +} + /* Separator */ .toolbar-divider {
diff --git a/third_party/WebKit/Source/devtools/tests/OWNERS b/third_party/WebKit/Source/devtools/tests/OWNERS new file mode 100644 index 0000000..72e8ffc --- /dev/null +++ b/third_party/WebKit/Source/devtools/tests/OWNERS
@@ -0,0 +1 @@ +*
diff --git a/third_party/WebKit/Source/devtools/tests/TestExpectations b/third_party/WebKit/Source/devtools/tests/TestExpectations index 856d613..41944a92 100644 --- a/third_party/WebKit/Source/devtools/tests/TestExpectations +++ b/third_party/WebKit/Source/devtools/tests/TestExpectations
@@ -20,6 +20,7 @@ inspector/console/worker-eval-contains-stack.html [ Skip ] inspector/sources/debugger-frameworks/frameworks-with-worker.html [ Skip ] inspector/sources/debugger-ui/script-snippet-model.html [ Skip ] # TODO(chenwilliam): extract the worker test +inspector/tracing/worker-events.html [ Skip ] # Skipping accessibility tests b/c of protocol change # https://crrev.com/3a46cc72d58945804dd4919a679a8ce26690bfc0 @@ -86,4 +87,12 @@ # Showing distribution for Shadow DOM V1 added after 1.2 protocol # https://crrev.com/e11af1f748a4236062fffa6b7db7dc5f79d20c7e -inspector/elements/shadow/shadow-distribution.html [ Skip ] \ No newline at end of file +inspector/elements/shadow/shadow-distribution.html [ Skip ] + +# Added frame information to timeline: +# crrev.com/79b4a4119de12f1f37748e7fedb3e2a87a534e3a +inspector-protocol/timeline/page-frames.html [ Skip ] + +# Added runtime stats to timeline: http://crbug.com/660428 +inspector/tracing/timeline-js/timeline-runtime-stats.html [ Skip ] +
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/http/tests/inspector/tracing/timeline-receive-response-event-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/http/tests/inspector/tracing/timeline-receive-response-event-expected.txt new file mode 100644 index 0000000..0a5fa4d --- /dev/null +++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/http/tests/inspector/tracing/timeline-receive-response-event-expected.txt
@@ -0,0 +1,15 @@ +Tests the Timeline API instrumentation of a SendRequest, ReceiveResponse etc. + + ResourceSendRequest +ResourceReceiveResponse +ResourceReceivedData +ResourceFinish +EventDispatch + FunctionCall + ResourceSendRequest +ResourceReceiveResponse +ResourceReceivedData +ResourceFinish +EventDispatch + FunctionCall +
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector-protocol/timeline/fetch-as-stream-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector-protocol/timeline/fetch-as-stream-expected.txt new file mode 100644 index 0000000..4941a14 --- /dev/null +++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector-protocol/timeline/fetch-as-stream-expected.txt
@@ -0,0 +1,8 @@ +Recording started +Tracing complete +Error after legit close: undefined +Error after illegal read: {"code":-32602,"message":"Missing or invalid 'Invalid stream handle' parameter"} +Error after illegal close: {"code":-32602,"message":"Missing or invalid 'Invalid stream handle' parameter"} +Event sanity test done +Metadata: object, not null +
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/tracing/timeline-js/timeline-js-line-level-profile-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/tracing/timeline-js/timeline-js-line-level-profile-expected.txt new file mode 100644 index 0000000..6d5667c2 --- /dev/null +++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/tracing/timeline-js/timeline-js-line-level-profile-expected.txt
@@ -0,0 +1,10 @@ +Tests that a line-level CPU profile is shown in the text editor. +.../inspector/tracing/resources/timeline-data.js +99 CodeMirror-gutter-performance 10.0 ms rgba(255, 187, 0, 0.262745) +101 CodeMirror-gutter-performance 1900.0 ms rgba(255, 187, 0, 0.717647) +0 CodeMirror-gutter-performance 100.0 ms rgba(255, 187, 0, 0.462745) +1 CodeMirror-gutter-performance 200.0 ms rgba(255, 187, 0, 0.521569) +2 CodeMirror-gutter-performance 300.0 ms rgba(255, 187, 0, 0.556863) +3 CodeMirror-gutter-performance 400.0 ms rgba(255, 187, 0, 0.580392) +54 CodeMirror-gutter-performance 220.0 ms rgba(255, 187, 0, 0.529412) +
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/tracing/timeline-js/timeline-script-tag-1-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/tracing/timeline-js/timeline-script-tag-1-expected.txt new file mode 100644 index 0000000..983ce0ba --- /dev/null +++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/tracing/timeline-js/timeline-script-tag-1-expected.txt
@@ -0,0 +1,19 @@ +CONSOLE MESSAGE: line 8: iframe loaded +Tests the Timeline API instrumentation of an HTML script tag. + + +EvaluateScript Properties: +{ + data : { + columnNumber : <number> + frame : <string> + lineNumber : <number> + url : .../inspector/tracing/resources/timeline-iframe-data.html + } + endTime : <number> + frameId : <string> + startTime : <number> + type : "EvaluateScript" +} +----> Timestamp: SCRIPT TAG +
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/tracing/timeline-js/timeline-script-tag-2-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/tracing/timeline-js/timeline-script-tag-2-expected.txt new file mode 100644 index 0000000..a7feeef9 --- /dev/null +++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/tracing/timeline-js/timeline-script-tag-2-expected.txt
@@ -0,0 +1,17 @@ +CONSOLE MESSAGE: line 1: SCRIPT TAG +Tests the Timeline API instrumentation of a script tag with an external script. + +EvaluateScript Properties: +{ + data : { + columnNumber : <number> + frame : <string> + lineNumber : <number> + url : .../inspector/tracing/timeline-js/timeline-script-tag-2.js + } + endTime : <number> + frameId : <string> + startTime : <number> + type : "EvaluateScript" +} +
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/tracing/timeline-network/timeline-network-resource-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/tracing/timeline-network/timeline-network-resource-expected.txt new file mode 100644 index 0000000..1a6c07c03 --- /dev/null +++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/tracing/timeline-network/timeline-network-resource-expected.txt
@@ -0,0 +1,50 @@ +Tests the Timeline API instrumentation of a network resource load + +Script resource loaded + +ResourceSendRequest Properties: +{ + data : { + frame : <string> + priority : "Low" + requestId : <string> + requestMethod : "GET" + stackTrace : <object> + url : .../inspector/tracing/resources/timeline-network-resource.js + } + endTime : <number> + frameId : <string> + stackTrace : <object> + startTime : <number> + type : "ResourceSendRequest" +} +Text details for ResourceSendRequest: timeline-network-resource.js + +ResourceReceiveResponse Properties: +{ + data : { + frame : <string> + mimeType : <string> + requestId : <string> + statusCode : 0 + } + endTime : <number> + frameId : <string> + startTime : <number> + type : "ResourceReceiveResponse" +} +Text details for ResourceReceiveResponse: timeline-network-resource.js + +ResourceFinish Properties: +{ + data : { + didFail : false + networkTime : <number> + requestId : <string> + } + endTime : <number> + startTime : <number> + type : "ResourceFinish" +} +Text details for ResourceFinish: timeline-network-resource.js +
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/tracing/timeline-time/timeline-time-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/tracing/timeline-time/timeline-time-expected.txt new file mode 100644 index 0000000..6c78afe --- /dev/null +++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/tracing/timeline-time/timeline-time-expected.txt
@@ -0,0 +1,14 @@ +Test nesting of time/timeEnd records on Timeline + + +Running: testSimpleConsoleTime + +Running: testNestedConsoleTime + +Running: testUnbalancedConsoleTime + +Running: testConsoleTimeWithoutConsoleTimeEnd +----> Timestamp: Foo +----> Timestamp: Bar +----> Timestamp: Baz +
diff --git a/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/tracing/timeline-time/timeline-timer-expected.txt b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/tracing/timeline-time/timeline-timer-expected.txt new file mode 100644 index 0000000..747ec425 --- /dev/null +++ b/third_party/WebKit/Source/devtools/tests/baseline/protocol-1.2/inspector/tracing/timeline-time/timeline-timer-expected.txt
@@ -0,0 +1,127 @@ +Tests the Timeline events for Timers + +TimerInstall Properties: +{ + data : { + frame : <string> + singleShot : true + stackTrace : <object> + timeout : 10 + timerId : <number> + } + endTime : <number> + frameId : <string> + stackTrace : <object> + startTime : <number> + type : "TimerInstall" +} +Text details for TimerInstall: timeline-timer.html:11 +TimerInstall Properties: +{ + data : { + frame : <string> + singleShot : false + stackTrace : <object> + timeout : 20 + timerId : <number> + } + endTime : <number> + frameId : <string> + stackTrace : <object> + startTime : <number> + type : "TimerInstall" +} +Text details for TimerInstall: timeline-timer.html:12 +TimerFire Properties: +{ + data : { + frame : <string> + timerId : <number> + } + endTime : <number> + frameId : <string> + startTime : <number> + type : "TimerFire" +} +Text details for TimerFire: timeline-timer.html:11 +TimerFire Properties: +{ + data : { + frame : <string> + timerId : <number> + } + endTime : <number> + frameId : <string> + startTime : <number> + type : "TimerFire" +} +Text details for TimerFire: timeline-timer.html:12 +TimerFire Properties: +{ + data : { + frame : <string> + timerId : <number> + } + endTime : <number> + frameId : <string> + startTime : <number> + type : "TimerFire" +} +Text details for TimerFire: timeline-timer.html:12 +TimerRemove Properties: +{ + data : { + frame : <string> + stackTrace : <object> + timerId : <number> + } + endTime : <number> + frameId : <string> + stackTrace : <object> + startTime : <number> + type : "TimerRemove" +} +Text details for TimerRemove: timeline-timer.html:19 +FunctionCall Properties: +{ + data : { + frame : <string> + functionName : "intervalTimerWork" + lineNumber : <number> + scriptId : <string> + url : .../inspector/tracing/timeline-time/timeline-timer.html + } + endTime : <number> + frameId : <string> + startTime : <number> + type : "FunctionCall" +} +FunctionCall Properties: +{ + data : { + frame : <string> + functionName : "intervalTimerWork" + lineNumber : <number> + scriptId : <string> + url : .../inspector/tracing/timeline-time/timeline-timer.html + } + endTime : <number> + frameId : <string> + startTime : <number> + type : "FunctionCall" +} +EvaluateScript Properties: +{ + data : { + columnNumber : <number> + frame : <string> + lineNumber : <number> + url : + } + endTime : <number> + frameId : <string> + startTime : <number> + type : "EvaluateScript" +} +Text details for EvaluateScript: undefined +
diff --git a/third_party/WebKit/Source/modules/ModulesInitializer.cpp b/third_party/WebKit/Source/modules/ModulesInitializer.cpp index 2108c94..4566746 100644 --- a/third_party/WebKit/Source/modules/ModulesInitializer.cpp +++ b/third_party/WebKit/Source/modules/ModulesInitializer.cpp
@@ -78,11 +78,4 @@ ASSERT(isInitialized()); } -void ModulesInitializer::shutdown() { - ASSERT(isInitialized()); - DatabaseManager::terminateDatabaseThread(); - CoreInitializer::shutdown(); - CompositorWorkerThread::clearSharedBackingThread(); -} - } // namespace blink
diff --git a/third_party/WebKit/Source/modules/ModulesInitializer.h b/third_party/WebKit/Source/modules/ModulesInitializer.h index 49d2c9334..5495b4f 100644 --- a/third_party/WebKit/Source/modules/ModulesInitializer.h +++ b/third_party/WebKit/Source/modules/ModulesInitializer.h
@@ -13,7 +13,6 @@ class MODULES_EXPORT ModulesInitializer : public CoreInitializer { public: void initialize() override; - void shutdown() override; }; } // namespace blink
diff --git a/third_party/WebKit/Source/modules/budget/OWNERS b/third_party/WebKit/Source/modules/budget/OWNERS index e3a1739..0db732d9 100644 --- a/third_party/WebKit/Source/modules/budget/OWNERS +++ b/third_party/WebKit/Source/modules/budget/OWNERS
@@ -1 +1,3 @@ peter@chromium.org + +# COMPONENT: Blink>PushAPI
diff --git a/third_party/WebKit/Source/modules/credentialmanager/OWNERS b/third_party/WebKit/Source/modules/credentialmanager/OWNERS index 3f84563..b731b26 100644 --- a/third_party/WebKit/Source/modules/credentialmanager/OWNERS +++ b/third_party/WebKit/Source/modules/credentialmanager/OWNERS
@@ -1 +1,3 @@ mkwst@chromium.org + +# COMPONENT: UI>Browser>Passwords
diff --git a/third_party/WebKit/Source/modules/gamepad/OWNERS b/third_party/WebKit/Source/modules/gamepad/OWNERS index 4adf627..1ed1f65 100644 --- a/third_party/WebKit/Source/modules/gamepad/OWNERS +++ b/third_party/WebKit/Source/modules/gamepad/OWNERS
@@ -1,2 +1,4 @@ b.kelemen@samsung.com bajones@chromium.org + +# COMPONENT: IO>Gamepad
diff --git a/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientationControllerImpl.cpp b/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientationControllerImpl.cpp index 3513dd49..d5eb971 100644 --- a/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientationControllerImpl.cpp +++ b/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientationControllerImpl.cpp
@@ -138,7 +138,7 @@ } void ScreenOrientationControllerImpl::notifyOrientationChanged() { - if (!isVisible()) + if (!isVisible() || !frame()) return; if (isActive())
diff --git a/third_party/WebKit/Source/modules/sensor/SensorProxy.cpp b/third_party/WebKit/Source/modules/sensor/SensorProxy.cpp index 226d9f7..9fb52ad6 100644 --- a/third_party/WebKit/Source/modules/sensor/SensorProxy.cpp +++ b/third_party/WebKit/Source/modules/sensor/SensorProxy.cpp
@@ -190,7 +190,8 @@ SensorClientRequest clientRequest) { DCHECK_EQ(Initializing, m_state); if (!params) { - handleSensorError(NotFoundError, "Sensor is not present on the platform."); + handleSensorError(NotReadableError, + "Sensor is not present on the platform."); return; } const size_t kReadBufferSize = sizeof(ReadingBuffer);
diff --git a/third_party/WebKit/Source/modules/serviceworkers/WaitUntilObserver.cpp b/third_party/WebKit/Source/modules/serviceworkers/WaitUntilObserver.cpp index f57dfb8..b02ff06 100644 --- a/third_party/WebKit/Source/modules/serviceworkers/WaitUntilObserver.cpp +++ b/third_party/WebKit/Source/modules/serviceworkers/WaitUntilObserver.cpp
@@ -86,12 +86,12 @@ void WaitUntilObserver::willDispatchEvent() { m_eventDispatchTime = WTF::currentTime(); - // When handling a notificationclick event, we want to allow one window to - // be focused or opened. These calls are allowed between the call to - // willDispatchEvent() and the last call to decrementPendingActivity(). If - // waitUntil() isn't called, that means between willDispatchEvent() and - // didDispatchEvent(). - if (m_type == NotificationClick) + // When handling a notificationclick or paymentrequest event, we want to + // allow one window to be focused or opened. These calls are allowed between + // the call to willDispatchEvent() and the last call to + // decrementPendingActivity(). If waitUntil() isn't called, that means + // between willDispatchEvent() and didDispatchEvent(). + if (m_type == NotificationClick || m_type == PaymentRequest) m_executionContext->allowWindowInteraction(); incrementPendingActivity();
diff --git a/third_party/WebKit/Source/modules/vr/OWNERS b/third_party/WebKit/Source/modules/vr/OWNERS index 21d4c8b..aa4627b 100644 --- a/third_party/WebKit/Source/modules/vr/OWNERS +++ b/third_party/WebKit/Source/modules/vr/OWNERS
@@ -1,2 +1,5 @@ bajones@chromium.org -kbr@chromium.org \ No newline at end of file +kbr@chromium.org + +# TEAM: hoverboard-team@chromium.org +# COMPONENT: Blink>WebVR
diff --git a/third_party/WebKit/Source/modules/vr/VRDisplay.cpp b/third_party/WebKit/Source/modules/vr/VRDisplay.cpp index 49e1cce..0c6bc0e 100644 --- a/third_party/WebKit/Source/modules/vr/VRDisplay.cpp +++ b/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
@@ -511,7 +511,7 @@ m_layer.setRightBounds({0.5f, 0.0f, 0.5f, 1.0f}); } - m_display->UpdateLayerBounds(m_frameId, std::move(leftBounds), + m_display->UpdateLayerBounds(m_vrFrameId, std::move(leftBounds), std::move(rightBounds)); } @@ -555,7 +555,7 @@ } // No frame Id to write before submitting the frame. - if (m_frameId < 0) { + if (m_vrFrameId < 0) { m_display->SubmitFrame(m_framePose.Clone()); return; } @@ -580,7 +580,7 @@ // Use the low byte of the index as the red component, and store an arbitrary // magic number in green/blue. This number must match the reading code in // vr_shell.cc. Avoid all-black/all-white. - gl->ClearColor((m_frameId & 255) / 255.0f, + gl->ClearColor((m_vrFrameId & 255) / 255.0f, kWebVrPosePixelMagicNumbers[0] / 255.0f, kWebVrPosePixelMagicNumbers[1] / 255.0f, 1.0f); gl->Clear(GL_COLOR_BUFFER_BIT); @@ -626,6 +626,8 @@ } void VRDisplay::OnActivate(device::mojom::blink::VRDisplayEventReason reason) { + if (!m_navigatorVR->isFocused() || m_displayBlurred) + return; m_navigatorVR->dispatchVRGestureEvent(VRDisplayEvent::create( EventTypeNames::vrdisplayactivate, true, false, this, reason)); } @@ -665,7 +667,7 @@ AutoReset<bool> animating(&m_inAnimationFrame, true); m_framePose = std::move(pose); - m_frameId = frameId; + m_vrFrameId = frameId; m_pendingRaf = false; m_scriptedAnimationController->serviceScriptedAnimations( m_timebase + timeDelta.InSecondsF());
diff --git a/third_party/WebKit/Source/modules/vr/VRDisplay.h b/third_party/WebKit/Source/modules/vr/VRDisplay.h index f81dd2b..2f0d66a6 100644 --- a/third_party/WebKit/Source/modules/vr/VRDisplay.h +++ b/third_party/WebKit/Source/modules/vr/VRDisplay.h
@@ -150,7 +150,11 @@ Member<VREyeParameters> m_eyeParametersLeft; Member<VREyeParameters> m_eyeParametersRight; device::mojom::blink::VRPosePtr m_framePose; - int16_t m_frameId = -1; + + // This frame ID is vr-specific and is used to track when frames arrive at the + // VR compositor so that it knows which poses to use, when to apply bounds + // updates, etc. + int16_t m_vrFrameId = -1; VRLayer m_layer; double m_depthNear = 0.01; double m_depthFar = 10000.0;
diff --git a/third_party/WebKit/Source/modules/webdatabase/DatabaseManager.cpp b/third_party/WebKit/Source/modules/webdatabase/DatabaseManager.cpp index 0eb1172..7902c51 100644 --- a/third_party/WebKit/Source/modules/webdatabase/DatabaseManager.cpp +++ b/third_party/WebKit/Source/modules/webdatabase/DatabaseManager.cpp
@@ -54,15 +54,6 @@ return *s_databaseManager; } -void DatabaseManager::terminateDatabaseThread() { - DCHECK(isMainThread()); - if (!s_databaseManager) - return; - for (const Member<DatabaseContext>& context : - s_databaseManager->m_contextMap.values()) - context->stopDatabases(); -} - DatabaseManager::DatabaseManager() { }
diff --git a/third_party/WebKit/Source/modules/webdatabase/DatabaseManager.h b/third_party/WebKit/Source/modules/webdatabase/DatabaseManager.h index 65ee92b5..669df89 100644 --- a/third_party/WebKit/Source/modules/webdatabase/DatabaseManager.h +++ b/third_party/WebKit/Source/modules/webdatabase/DatabaseManager.h
@@ -48,7 +48,6 @@ public: static DatabaseManager& manager(); - static void terminateDatabaseThread(); // These 2 methods are for DatabaseContext (un)registration, and should only // be called by the DatabaseContext constructor and destructor.
diff --git a/third_party/WebKit/Source/modules/webgl/OWNERS b/third_party/WebKit/Source/modules/webgl/OWNERS index d749de68..7429f365 100644 --- a/third_party/WebKit/Source/modules/webgl/OWNERS +++ b/third_party/WebKit/Source/modules/webgl/OWNERS
@@ -1,3 +1,5 @@ bajones@chromium.org kbr@chromium.org -zmo@chromium.org \ No newline at end of file +zmo@chromium.org + +# COMPONENT: Blink>WebGL
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn index 6176634d..290e42c 100644 --- a/third_party/WebKit/Source/platform/BUILD.gn +++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -405,14 +405,10 @@ "audio/AudioDestination.cpp", "audio/AudioDestination.h", "audio/AudioDestinationConsumer.h", - "audio/AudioFIFO.cpp", - "audio/AudioFIFO.h", "audio/AudioFileReader.h", "audio/AudioIOCallback.h", "audio/AudioProcessor.cpp", "audio/AudioProcessor.h", - "audio/AudioPullFIFO.cpp", - "audio/AudioPullFIFO.h", "audio/AudioResampler.cpp", "audio/AudioResampler.h", "audio/AudioResamplerKernel.cpp", @@ -459,6 +455,8 @@ "audio/MultiChannelResampler.h", "audio/Panner.cpp", "audio/Panner.h", + "audio/PushPullFIFO.cpp", + "audio/PushPullFIFO.h", "audio/Reverb.cpp", "audio/Reverb.h", "audio/ReverbAccumulationBuffer.cpp", @@ -491,8 +489,6 @@ "clipboard/ClipboardMimeTypes.h", "clipboard/ClipboardUtilities.cpp", "clipboard/ClipboardUtilities.h", - "clipboard/ClipboardUtilitiesPosix.cpp", - "clipboard/ClipboardUtilitiesWin.cpp", "cpu/mips/CommonMacrosMSA.h", "credentialmanager/PlatformCredential.cpp", "credentialmanager/PlatformCredential.h", @@ -508,6 +504,7 @@ "exported/WebAudioBus.cpp", "exported/WebAudioDevice.cpp", "exported/WebBlobData.cpp", + "exported/WebCache.cpp", "exported/WebCanvasCaptureHandler.cpp", "exported/WebContentDecryptionModule.cpp", "exported/WebContentDecryptionModuleAccess.cpp", @@ -1005,6 +1002,7 @@ "graphics/paint/FilterDisplayItem.h", "graphics/paint/FloatClipDisplayItem.cpp", "graphics/paint/FloatClipDisplayItem.h", + "graphics/paint/FloatClipRect.h", "graphics/paint/ForeignLayerDisplayItem.cpp", "graphics/paint/ForeignLayerDisplayItem.h", "graphics/paint/GeometryMapper.cpp", @@ -1512,9 +1510,8 @@ } if (is_win) { + sources += [ "clipboard/ClipboardUtilitiesWin.cpp" ] sources -= [ - "clipboard/ClipboardUtilitiesPosix.cpp", - # Uses LocaleWin instead. "text/LocaleICU.cpp", "text/LocaleICU.h", @@ -1524,10 +1521,7 @@ "/wd4724", # Modulo by 0. ] } else { - sources -= [ - "clipboard/ClipboardUtilitiesWin.cpp", - "text/LocaleWin.cpp", - ] + sources -= [ "text/LocaleWin.cpp" ] } if (is_android) { @@ -1701,8 +1695,8 @@ "animation/CompositorAnimationTimelineTest.cpp", "animation/CompositorFloatAnimationCurveTest.cpp", "animation/TimingFunctionTest.cpp", + "audio/PushPullFIFOTest.cpp", "blob/BlobDataTest.cpp", - "clipboard/ClipboardUtilitiesTest.cpp", "exported/FilePathConversionTest.cpp", "exported/WebStringTest.cpp", "feature_policy/FeaturePolicyTest.cpp",
diff --git a/third_party/WebKit/Source/platform/MemoryCoordinator.cpp b/third_party/WebKit/Source/platform/MemoryCoordinator.cpp index 4882b3d..b414dbf4 100644 --- a/third_party/WebKit/Source/platform/MemoryCoordinator.cpp +++ b/third_party/WebKit/Source/platform/MemoryCoordinator.cpp
@@ -65,8 +65,12 @@ void MemoryCoordinator::onMemoryStateChange(MemoryState state) { for (auto& client : m_clients) client->onMemoryStateChange(state); + // Font cache invalidation always causes full layout. This increases + // tab switching cost significantly (e.g. en.wikipedia.org/wiki/Wikipedia). + // So we should not invalidate the font cache in purge+throttle. We should + // invalidate the font cache only when receiving a critical memory pressure. if (state == MemoryState::SUSPENDED) - clearMemory(); + ImageDecodingStore::instance().clear(); WTF::Partitions::decommitFreeableMemory(); }
diff --git a/third_party/WebKit/Source/platform/audio/AudioDestination.cpp b/third_party/WebKit/Source/platform/audio/AudioDestination.cpp index dcf0ea58..70ca828e 100644 --- a/third_party/WebKit/Source/platform/audio/AudioDestination.cpp +++ b/third_party/WebKit/Source/platform/audio/AudioDestination.cpp
@@ -28,14 +28,14 @@ #include "platform/audio/AudioDestination.h" +#include <memory> #include "platform/Histogram.h" -#include "platform/audio/AudioPullFIFO.h" #include "platform/audio/AudioUtilities.h" +#include "platform/audio/PushPullFIFO.h" #include "platform/weborigin/SecurityOrigin.h" #include "public/platform/Platform.h" #include "public/platform/WebSecurityOrigin.h" #include "wtf/PtrUtil.h" -#include <memory> namespace blink { @@ -67,6 +67,8 @@ m_outputBus(AudioBus::create(numberOfOutputChannels, AudioUtilities::kRenderQuantumFrames, false)), + m_renderBus(AudioBus::create(numberOfOutputChannels, + AudioUtilities::kRenderQuantumFrames)), m_framesElapsed(0) { // Calculate the optimum buffer size first. if (calculateBufferSize()) { @@ -80,9 +82,8 @@ DCHECK(m_webAudioDevice); // Create a FIFO. - m_fifo = WTF::wrapUnique( - new AudioPullFIFO(*this, numberOfOutputChannels, kFIFOSize, - AudioUtilities::kRenderQuantumFrames)); + m_fifo = + WTF::wrapUnique(new PushPullFIFO(numberOfOutputChannels, kFIFOSize)); } else { NOTREACHED(); } @@ -97,13 +98,8 @@ double delay, double delayTimestamp, size_t priorFramesSkipped) { - DCHECK_EQ(destinationData.size(), m_numberOfOutputChannels); - if (destinationData.size() != m_numberOfOutputChannels) - return; - - DCHECK_EQ(numberOfFrames, m_callbackBufferSize); - if (numberOfFrames != m_callbackBufferSize) - return; + CHECK_EQ(destinationData.size(), m_numberOfOutputChannels); + CHECK_EQ(numberOfFrames, m_callbackBufferSize); m_framesElapsed -= std::min(m_framesElapsed, priorFramesSkipped); double outputPosition = @@ -116,32 +112,41 @@ // FIFO. for (unsigned i = 0; i < m_numberOfOutputChannels; ++i) m_outputBus->setChannelMemory(i, destinationData[i], numberOfFrames); - m_fifo->consume(m_outputBus.get(), numberOfFrames); - m_framesElapsed += numberOfFrames; -} + // Number of frames to render via WebAudio graph. |framesToRender > 0| means + // the frames in FIFO is not enough to fulfill the requested frames from the + // audio device. + size_t framesToRender = numberOfFrames > m_fifo->framesAvailable() + ? numberOfFrames - m_fifo->framesAvailable() + : 0; -void AudioDestination::provideInput(AudioBus* outputBus, - size_t framesToProcess) { - AudioIOPosition outputPosition = m_outputPosition; + for (size_t pushedFrames = 0; pushedFrames < framesToRender; + pushedFrames += AudioUtilities::kRenderQuantumFrames) { + // If platform buffer is more than two times longer than |framesToProcess| + // we do not want output position to get stuck so we promote it + // using the elapsed time from the moment it was initially obtained. + if (m_callbackBufferSize > AudioUtilities::kRenderQuantumFrames * 2) { + double delta = + (base::TimeTicks::Now() - m_outputPositionReceivedTimestamp) + .InSecondsF(); + m_outputPosition.position += delta; + m_outputPosition.timestamp += delta; + } - // If platform buffer is more than two times longer than |framesToProcess| - // we do not want output position to get stuck so we promote it - // using the elapsed time from the moment it was initially obtained. - if (m_callbackBufferSize > framesToProcess * 2) { - double delta = (base::TimeTicks::Now() - m_outputPositionReceivedTimestamp) - .InSecondsF(); - outputPosition.position += delta; - outputPosition.timestamp += delta; + // Some implementations give only rough estimation of |delay| so + // we might have negative estimation |outputPosition| value. + if (m_outputPosition.position < 0.0) + m_outputPosition.position = 0.0; + + // Process WebAudio graph and push the rendered output to FIFO. + m_callback.render(nullptr, m_renderBus.get(), + AudioUtilities::kRenderQuantumFrames, m_outputPosition); + m_fifo->push(m_renderBus.get()); } - // Some implementations give only rough estimation of |delay| so - // we might have negative estimation |outputPosition| value. - if (outputPosition.position < 0.0) - outputPosition.position = 0.0; + m_fifo->pull(m_outputBus.get(), numberOfFrames); - // To fill the FIFO, start the render call chain of the destination node. - m_callback.render(nullptr, outputBus, framesToProcess, outputPosition); + m_framesElapsed += numberOfFrames; } void AudioDestination::start() {
diff --git a/third_party/WebKit/Source/platform/audio/AudioDestination.h b/third_party/WebKit/Source/platform/audio/AudioDestination.h index d0e35b8..f5c699a1 100644 --- a/third_party/WebKit/Source/platform/audio/AudioDestination.h +++ b/third_party/WebKit/Source/platform/audio/AudioDestination.h
@@ -31,7 +31,6 @@ #include "platform/audio/AudioBus.h" #include "platform/audio/AudioIOCallback.h" -#include "platform/audio/AudioSourceProvider.h" #include "public/platform/WebAudioDevice.h" #include "public/platform/WebVector.h" #include "wtf/Allocator.h" @@ -41,15 +40,14 @@ namespace blink { -class AudioPullFIFO; +class PushPullFIFO; class SecurityOrigin; // The AudioDestination class is an audio sink interface between the media // renderer and the Blink's WebAudio module. It has a FIFO to adapt the // different processing block sizes of WebAudio renderer and actual hardware // audio callback. -class PLATFORM_EXPORT AudioDestination : public WebAudioDevice::RenderCallback, - public AudioSourceProvider { +class PLATFORM_EXPORT AudioDestination : public WebAudioDevice::RenderCallback { USING_FAST_MALLOC(AudioDestination); WTF_MAKE_NONCOPYABLE(AudioDestination); @@ -74,9 +72,6 @@ double delayTimestamp, size_t priorFramesSkipped) override; - // AudioSourceProvider (FIFO) - void provideInput(AudioBus* outputBus, size_t framesToProcess) override; - virtual void start(); virtual void stop(); @@ -98,8 +93,15 @@ // The render callback function of WebAudio engine. (i.e. DestinationNode) AudioIOCallback& m_callback; + // To pass the data from FIFO to the audio device callback. RefPtr<AudioBus> m_outputBus; - std::unique_ptr<AudioPullFIFO> m_fifo; + + // To push the rendered result from WebAudio graph into the FIFO. + RefPtr<AudioBus> m_renderBus; + + // Resolves the buffer size mismatch between the WebAudio engine and + // the callback function from the actual audio device. + std::unique_ptr<PushPullFIFO> m_fifo; size_t m_framesElapsed; AudioIOPosition m_outputPosition;
diff --git a/third_party/WebKit/Source/platform/audio/AudioFIFO.cpp b/third_party/WebKit/Source/platform/audio/AudioFIFO.cpp deleted file mode 100644 index c35ce14..0000000 --- a/third_party/WebKit/Source/platform/audio/AudioFIFO.cpp +++ /dev/null
@@ -1,146 +0,0 @@ -/* - * Copyright (C) 2012 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: - * - * 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. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE 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. - */ - -#include "platform/audio/AudioFIFO.h" - -namespace blink { - -AudioFIFO::AudioFIFO(unsigned numberOfChannels, size_t fifoLength) - : m_fifoAudioBus(AudioBus::create(numberOfChannels, fifoLength)), - m_fifoLength(fifoLength), - m_framesInFifo(0), - m_readIndex(0), - m_writeIndex(0) {} - -void AudioFIFO::consume(AudioBus* destination, size_t framesToConsume) { - bool isGood = destination && (framesToConsume <= m_fifoLength) && - (framesToConsume <= m_framesInFifo) && - (destination->length() >= framesToConsume); - ASSERT(isGood); - if (!isGood) - return; - - // Copy the requested number of samples to the destination. - - size_t part1Length; - size_t part2Length; - findWrapLengths(m_readIndex, framesToConsume, part1Length, part2Length); - - size_t numberOfChannels = m_fifoAudioBus->numberOfChannels(); - - for (size_t channelIndex = 0; channelIndex < numberOfChannels; - ++channelIndex) { - float* destinationData = destination->channel(channelIndex)->mutableData(); - const float* sourceData = m_fifoAudioBus->channel(channelIndex)->data(); - - bool isCopyGood = ((m_readIndex < m_fifoLength) && - (m_readIndex + part1Length) <= m_fifoLength && - (part1Length <= destination->length()) && - (part1Length + part2Length) <= destination->length()); - ASSERT(isCopyGood); - if (!isCopyGood) - return; - - memcpy(destinationData, sourceData + m_readIndex, - part1Length * sizeof(*sourceData)); - // Handle wrap around of the FIFO, if needed. - if (part2Length) - memcpy(destinationData + part1Length, sourceData, - part2Length * sizeof(*sourceData)); - } - m_readIndex = updateIndex(m_readIndex, framesToConsume); - ASSERT(m_framesInFifo >= framesToConsume); - m_framesInFifo -= framesToConsume; -} - -void AudioFIFO::push(const AudioBus* sourceBus) { - // Copy the sourceBus into the FIFO buffer. - - bool isGood = - sourceBus && (m_framesInFifo + sourceBus->length() <= m_fifoLength); - if (!isGood) - return; - - size_t sourceLength = sourceBus->length(); - size_t part1Length; - size_t part2Length; - findWrapLengths(m_writeIndex, sourceLength, part1Length, part2Length); - - size_t numberOfChannels = m_fifoAudioBus->numberOfChannels(); - - for (size_t channelIndex = 0; channelIndex < numberOfChannels; - ++channelIndex) { - float* destination = m_fifoAudioBus->channel(channelIndex)->mutableData(); - const float* source = sourceBus->channel(channelIndex)->data(); - - bool isCopyGood = ((m_writeIndex < m_fifoLength) && - (m_writeIndex + part1Length) <= m_fifoLength && - part2Length < m_fifoLength && - part1Length + part2Length <= sourceLength); - ASSERT(isCopyGood); - if (!isCopyGood) - return; - - memcpy(destination + m_writeIndex, source, - part1Length * sizeof(*destination)); - - // Handle wrap around of the FIFO, if needed. - if (part2Length) - memcpy(destination, source + part1Length, - part2Length * sizeof(*destination)); - } - - m_framesInFifo += sourceLength; - ASSERT(m_framesInFifo <= m_fifoLength); - m_writeIndex = updateIndex(m_writeIndex, sourceLength); -} - -void AudioFIFO::findWrapLengths(size_t index, - size_t size, - size_t& part1Length, - size_t& part2Length) { - SECURITY_DCHECK(index < m_fifoLength && size <= m_fifoLength); - if (index < m_fifoLength && size <= m_fifoLength) { - if (index + size > m_fifoLength) { - // Need to wrap. Figure out the length of each piece. - part1Length = m_fifoLength - index; - part2Length = size - part1Length; - } else { - // No wrap needed. - part1Length = size; - part2Length = 0; - } - } else { - // Invalid values for index or size. Set the part lengths to zero so nothing - // is copied. - part1Length = 0; - part2Length = 0; - } -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/platform/audio/AudioFIFO.h b/third_party/WebKit/Source/platform/audio/AudioFIFO.h deleted file mode 100644 index ef66f92..0000000 --- a/third_party/WebKit/Source/platform/audio/AudioFIFO.h +++ /dev/null
@@ -1,84 +0,0 @@ -/* - * Copyright (C) 2012 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: - * - * 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. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE 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. - */ - -#ifndef AudioFIFO_h -#define AudioFIFO_h - -#include "platform/audio/AudioBus.h" -#include "wtf/Allocator.h" - -namespace blink { - -class AudioFIFO { - USING_FAST_MALLOC(AudioFIFO); - WTF_MAKE_NONCOPYABLE(AudioFIFO); - - public: - // Create a FIFO large enough to hold |fifoLength| frames of data of - // |numberOfChannels| channels. - AudioFIFO(unsigned numberOfChannels, size_t fifoLength); - - // Push the data from the bus into the FIFO. - void push(const AudioBus*); - - // Consume |framesToConsume| frames of data from the FIFO and put them in - // |destination|. The corresponding frames are removed from the FIFO. - void consume(AudioBus* destination, size_t framesToConsume); - - // Number of frames of data that are currently in the FIFO. - size_t framesInFifo() const { return m_framesInFifo; } - - private: - // Update the FIFO index by the step, with appropriate wrapping around the - // endpoint. - int updateIndex(int index, int step) { return (index + step) % m_fifoLength; } - - void findWrapLengths(size_t index, - size_t providerSize, - size_t& part1Length, - size_t& part2Length); - - // The FIFO itself. In reality, the FIFO is a circular buffer. - RefPtr<AudioBus> m_fifoAudioBus; - - // The total available space in the FIFO. - size_t m_fifoLength; - - // The number of actual elements in the FIFO - size_t m_framesInFifo; - - // Where to start reading from the FIFO. - size_t m_readIndex; - - // Where to start writing to the FIFO. - size_t m_writeIndex; -}; - -} // namespace blink - -#endif // AudioFIFO.h
diff --git a/third_party/WebKit/Source/platform/audio/AudioPullFIFO.cpp b/third_party/WebKit/Source/platform/audio/AudioPullFIFO.cpp deleted file mode 100644 index ca14cfa..0000000 --- a/third_party/WebKit/Source/platform/audio/AudioPullFIFO.cpp +++ /dev/null
@@ -1,69 +0,0 @@ -/* - * Copyright (C) 2012 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: - * - * 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. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE 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. - */ - -#include "platform/audio/AudioPullFIFO.h" - -namespace blink { - -AudioPullFIFO::AudioPullFIFO(AudioSourceProvider& audioProvider, - unsigned numberOfChannels, - size_t fifoLength, - size_t providerSize) - : m_provider(audioProvider), - m_fifo(numberOfChannels, fifoLength), - m_providerSize(providerSize), - m_tempBus(AudioBus::create(numberOfChannels, providerSize)) {} - -void AudioPullFIFO::consume(AudioBus* destination, size_t framesToConsume) { - if (!destination) - return; - - if (framesToConsume > m_fifo.framesInFifo()) { - // We don't have enough data in the FIFO to fulfill the request. Ask for - // more data. - fillBuffer(framesToConsume - m_fifo.framesInFifo()); - } - - m_fifo.consume(destination, framesToConsume); -} - -void AudioPullFIFO::fillBuffer(size_t numberOfFrames) { - // Keep asking the provider to give us data until we have received at least - // |numberOfFrames| of data. Stuff the data into the FIFO. - size_t framesProvided = 0; - - while (framesProvided < numberOfFrames) { - m_provider.provideInput(m_tempBus.get(), m_providerSize); - - m_fifo.push(m_tempBus.get()); - - framesProvided += m_providerSize; - } -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/platform/audio/AudioPullFIFO.h b/third_party/WebKit/Source/platform/audio/AudioPullFIFO.h deleted file mode 100644 index 7f375b2e..0000000 --- a/third_party/WebKit/Source/platform/audio/AudioPullFIFO.h +++ /dev/null
@@ -1,84 +0,0 @@ -/* - * Copyright (C) 2012 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: - * - * 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. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE 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. - */ - -#ifndef AudioPullFIFO_h -#define AudioPullFIFO_h - -#include "platform/audio/AudioBus.h" -#include "platform/audio/AudioFIFO.h" -#include "platform/audio/AudioSourceProvider.h" -#include "wtf/Allocator.h" - -namespace blink { - -// A FIFO (First In First Out) buffer to handle mismatches in buffer sizes -// between a provider and receiver. The receiver will "pull" data from this -// FIFO. If data is already available in the FIFO, it is provided to the -// receiver. If insufficient data is available to satisfy the request, the FIFO -// will ask the provider for more data when necessary to fulfill a request. -// Contrast this with a "push" FIFO, where the sender pushes data to the FIFO -// which will itself push the data to the receiver when the FIFO is full. -class PLATFORM_EXPORT AudioPullFIFO { - USING_FAST_MALLOC(AudioPullFIFO); - WTF_MAKE_NONCOPYABLE(AudioPullFIFO); - - public: - // Create a FIFO that gets data from |provider|. The FIFO will be large - // enough to hold |fifoLength| frames of data of |numberOfChannels| channels. - // The AudioSourceProvider will be asked to produce |providerSize| frames - // when the FIFO needs more data. - AudioPullFIFO(AudioSourceProvider& audioProvider, - unsigned numberOfChannels, - size_t fifoLength, - size_t providerSize); - - // Read |framesToConsume| frames from the FIFO into the destination. If the - // FIFO does not have enough data, we ask the |provider| to get more data to - // fulfill the request. - void consume(AudioBus* destination, size_t framesToConsume); - - private: - // Fill the FIFO buffer with at least |numberOfFrames| more data. - void fillBuffer(size_t numberOfFrames); - - // The provider of the data in our FIFO. - AudioSourceProvider& m_provider; - - // The actual FIFO - AudioFIFO m_fifo; - - // Number of frames of data that the provider will produce per call. - unsigned m_providerSize; - - // Temporary workspace to hold the data from the provider. - RefPtr<AudioBus> m_tempBus; -}; - -} // namespace blink - -#endif // AudioPullFIFO.h
diff --git a/third_party/WebKit/Source/platform/audio/PushPullFIFO.cpp b/third_party/WebKit/Source/platform/audio/PushPullFIFO.cpp new file mode 100644 index 0000000..f464e9d --- /dev/null +++ b/third_party/WebKit/Source/platform/audio/PushPullFIFO.cpp
@@ -0,0 +1,145 @@ +// 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 "platform/audio/PushPullFIFO.h" + +#include <memory> +#include "platform/audio/AudioUtilities.h" +#include "wtf/PtrUtil.h" + +namespace blink { + +namespace { + +// Suppress the warning log if over/underflow happens more than 100 times. +const unsigned kMaxMessagesToLog = 100; +} + +const size_t PushPullFIFO::kMaxFIFOLength = 65536; + +PushPullFIFO::PushPullFIFO(unsigned numberOfChannels, size_t fifoLength) + : m_fifoLength(fifoLength), + m_framesAvailable(0), + m_indexRead(0), + m_indexWrite(0), + m_overflowCount(0), + m_underflowCount(0) { + CHECK_LE(m_fifoLength, kMaxFIFOLength); + m_fifoBus = AudioBus::create(numberOfChannels, m_fifoLength); +} + +PushPullFIFO::~PushPullFIFO() {} + +// Push the data from |inputBus| to FIFO. The size of push is determined by +// the length of |inputBus|. +void PushPullFIFO::push(const AudioBus* inputBus) { + CHECK(inputBus); + CHECK_EQ(inputBus->length(), AudioUtilities::kRenderQuantumFrames); + SECURITY_CHECK(inputBus->length() <= m_fifoLength); + SECURITY_CHECK(m_indexWrite < m_fifoLength); + + const size_t inputBusLength = inputBus->length(); + const size_t remainder = m_fifoLength - m_indexWrite; + + for (unsigned i = 0; i < m_fifoBus->numberOfChannels(); ++i) { + float* fifoBusChannel = m_fifoBus->channel(i)->mutableData(); + const float* inputBusChannel = inputBus->channel(i)->data(); + if (remainder >= inputBusLength) { + // The remainder is big enough for the input data. + memcpy(fifoBusChannel + m_indexWrite, inputBusChannel, + inputBusLength * sizeof(*fifoBusChannel)); + } else { + // The input data overflows the remainder size. Wrap around the index. + memcpy(fifoBusChannel + m_indexWrite, inputBusChannel, + remainder * sizeof(*fifoBusChannel)); + memcpy(fifoBusChannel, inputBusChannel + remainder, + (inputBusLength - remainder) * sizeof(*fifoBusChannel)); + } + } + + // Update the write index; wrap it around if necessary. + m_indexWrite = (m_indexWrite + inputBusLength) % m_fifoLength; + + // In case of overflow, move the |indexRead| to the updated |indexWrite| to + // avoid reading overwritten frames by the next pull. + if (inputBusLength > m_fifoLength - m_framesAvailable) { + m_indexRead = m_indexWrite; + if (++m_overflowCount < kMaxMessagesToLog) { + LOG(WARNING) << "PushPullFIFO: overflow while pushing (" + << "overflowCount=" << m_overflowCount + << ", availableFrames=" << m_framesAvailable + << ", inputFrames=" << inputBusLength + << ", fifoLength=" << m_fifoLength << ")"; + } + } + + // Update the number of frames available in FIFO. + m_framesAvailable = + std::min(m_framesAvailable + inputBusLength, m_fifoLength); + DCHECK_EQ((m_indexRead + m_framesAvailable) % m_fifoLength, m_indexWrite); +} + +// Pull the data out of FIFO to |outputBus|. If remaining frame in the FIFO +// is less than the frames to pull, provides remaining frame plus the silence. +void PushPullFIFO::pull(AudioBus* outputBus, size_t framesRequested) { + CHECK(outputBus); + SECURITY_CHECK(framesRequested <= outputBus->length()); + SECURITY_CHECK(framesRequested <= m_fifoLength); + SECURITY_CHECK(m_indexRead < m_fifoLength); + + const size_t remainder = m_fifoLength - m_indexRead; + const size_t framesToFill = std::min(m_framesAvailable, framesRequested); + + for (unsigned i = 0; i < m_fifoBus->numberOfChannels(); ++i) { + const float* fifoBusChannel = m_fifoBus->channel(i)->data(); + float* outputBusChannel = outputBus->channel(i)->mutableData(); + + // Fill up the output bus with the available frames first. + if (remainder >= framesToFill) { + // The remainder is big enough for the frames to pull. + memcpy(outputBusChannel, fifoBusChannel + m_indexRead, + framesToFill * sizeof(*fifoBusChannel)); + } else { + // The frames to pull is bigger than the remainder size. + // Wrap around the index. + memcpy(outputBusChannel, fifoBusChannel + m_indexRead, + remainder * sizeof(*fifoBusChannel)); + memcpy(outputBusChannel + remainder, fifoBusChannel, + (framesToFill - remainder) * sizeof(*fifoBusChannel)); + } + + // The frames available was not enough to fulfill the requested frames. Fill + // the rest of the channel with silence. + if (framesRequested > framesToFill) { + memset(outputBusChannel + framesToFill, 0, + (framesRequested - framesToFill) * sizeof(*outputBusChannel)); + } + } + + // Update the read index; wrap it around if necessary. + m_indexRead = (m_indexRead + framesToFill) % m_fifoLength; + + // In case of underflow, move the |indexWrite| to the updated |indexRead|. + if (framesRequested > framesToFill) { + m_indexWrite = m_indexRead; + if (m_underflowCount++ < kMaxMessagesToLog) { + LOG(WARNING) << "PushPullFIFO: underflow while pulling (" + << "underflowCount=" << m_underflowCount + << ", availableFrames=" << m_framesAvailable + << ", requestedFrames=" << framesRequested + << ", fifoLength=" << m_fifoLength << ")"; + } + } + + // Update the number of frames in FIFO. + m_framesAvailable -= framesToFill; + DCHECK_EQ((m_indexRead + m_framesAvailable) % m_fifoLength, m_indexWrite); +} + +const PushPullFIFOStateForTest PushPullFIFO::getStateForTest() const { + return {length(), numberOfChannels(), framesAvailable(), m_indexRead, + m_indexWrite, m_overflowCount, m_underflowCount}; +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/audio/PushPullFIFO.h b/third_party/WebKit/Source/platform/audio/PushPullFIFO.h new file mode 100644 index 0000000..2341372 --- /dev/null +++ b/third_party/WebKit/Source/platform/audio/PushPullFIFO.h
@@ -0,0 +1,85 @@ +// 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 PushPullFIFO_h +#define PushPullFIFO_h + +#include "platform/audio/AudioBus.h" +#include "public/platform/WebCommon.h" +#include "wtf/Allocator.h" + +namespace blink { + +// A configuration data container for PushPullFIFO unit test. +struct PushPullFIFOStateForTest { + const size_t fifoLength; + const unsigned numberOfChannels; + const size_t framesAvailable; + const size_t indexRead; + const size_t indexWrite; + const unsigned overflowCount; + const unsigned underflowCount; +}; + +// PushPullFIFO class is an intermediate audio sample storage between +// Blink-WebAudio and the renderer. The renderer's hardware callback buffer size +// varies on the platform, but the WebAudio always renders 128 frames (render +// quantum, RQ) thus FIFO is needed to handle the general case. +class BLINK_PLATFORM_EXPORT PushPullFIFO { + USING_FAST_MALLOC(PushPullFIFO); + WTF_MAKE_NONCOPYABLE(PushPullFIFO); + + public: + // Maximum FIFO length. (512 render quanta) + static const size_t kMaxFIFOLength; + + // |fifoLength| cannot exceed |kMaxFIFOLength|. Otherwise it crashes. + explicit PushPullFIFO(unsigned numberOfChannels, size_t fifoLength); + ~PushPullFIFO(); + + // Pushes the rendered frames by WebAudio engine. + // - The |inputBus| length is 128 frames (1 render quantum), fixed. + // - In case of overflow (FIFO full while push), the existing frames in FIFO + // will be overwritten and |indexRead| will be forcibly moved to + // |indexWrite| to avoid reading overwritten frames. + void push(const AudioBus* inputBus); + + // Pulling |framesRequested| by the audio device thread. + // - If |framesRequested| is bigger than the length of |outputBus|, it + // violates SECURITY_CHECK(). + // - If |framesRequested| is bigger than FIFO length, it violates + // SECURITY_CHECK(). + // - In case of underflow (FIFO empty while pull), the remaining space in the + // requested output bus will be filled with silence. Thus it will fulfill + // the request from the consumer without causing error, but with a glitch. + void pull(AudioBus* outputBus, size_t framesRequested); + + size_t framesAvailable() const { return m_framesAvailable; } + size_t length() const { return m_fifoLength; } + unsigned numberOfChannels() const { return m_fifoBus->numberOfChannels(); } + AudioBus* bus() const { return m_fifoBus.get(); } + + // For unit test. Get the current configuration that consists of FIFO length, + // number of channels, read/write index position and under/overflow count. + const PushPullFIFOStateForTest getStateForTest() const; + + private: + // The size of the FIFO. + const size_t m_fifoLength = 0; + + RefPtr<AudioBus> m_fifoBus; + + // The number of frames in the FIFO actually available for pulling. + size_t m_framesAvailable; + + size_t m_indexRead; + size_t m_indexWrite; + + unsigned m_overflowCount; + unsigned m_underflowCount; +}; + +} // namespace blink + +#endif // PushPullFIFO_h
diff --git a/third_party/WebKit/Source/platform/audio/PushPullFIFOTest.cpp b/third_party/WebKit/Source/platform/audio/PushPullFIFOTest.cpp new file mode 100644 index 0000000..0a9edda2 --- /dev/null +++ b/third_party/WebKit/Source/platform/audio/PushPullFIFOTest.cpp
@@ -0,0 +1,364 @@ +// 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 "platform/audio/PushPullFIFO.h" + +#include <memory> +#include <vector> +#include "platform/audio/AudioUtilities.h" +#include "platform/testing/TestingPlatformSupport.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "wtf/PtrUtil.h" + +namespace blink { + +namespace { + +// Check the basic contract of FIFO. +TEST(PushPullFIFOBasicTest, BasicTests) { + // This suppresses the multi-thread warning for GTest. Potently it increases + // the test execution time, but this specific test is very short and simple. + ::testing::FLAGS_gtest_death_test_style = "threadsafe"; + + // FIFO length exceeding the maximum length allowed will cause crash. + EXPECT_DEATH(new PushPullFIFO(2, PushPullFIFO::kMaxFIFOLength + 1), + "m_fifoLength <= kMaxFIFOLength"); + + std::unique_ptr<PushPullFIFO> testFifo = + WTF::wrapUnique(new PushPullFIFO(2, 1024)); + + // The input bus length must be |AudioUtilities::kRenderQuantumFrames|. + RefPtr<AudioBus> inputBusOf129Frames = + AudioBus::create(2, AudioUtilities::kRenderQuantumFrames + 1); + EXPECT_DEATH(testFifo->push(inputBusOf129Frames.get()), + "inputBus->length.* == .*kRenderQuantumFrames"); + RefPtr<AudioBus> inputBusOf127Frames = + AudioBus::create(2, AudioUtilities::kRenderQuantumFrames - 1); + EXPECT_DEATH(testFifo->push(inputBusOf127Frames.get()), + "inputBus->length.* == .*kRenderQuantumFrames"); + + // Pull request frames cannot exceed the length of output bus. + RefPtr<AudioBus> outputBusOf512Frames = AudioBus::create(2, 512); + EXPECT_DEATH(testFifo->pull(outputBusOf512Frames.get(), 513), + "framesRequested <= outputBus->length.*"); + + // Pull request frames cannot exceed the length of FIFO. + RefPtr<AudioBus> outputBusOf1025Frames = AudioBus::create(2, 1025); + EXPECT_DEATH(testFifo->pull(outputBusOf1025Frames.get(), 1025), + "framesRequested <= m_fifoLength"); +} + +// Fills each AudioChannel in an AudioBus with a series of linearly increasing +// values starting from |startingValue| and incrementing by 1. Then return value +// will be |startingValue| + |bus_length|. +size_t fillBusWithLinearRamp(AudioBus* targetBus, size_t startingValue) { + for (unsigned c = 0; c < targetBus->numberOfChannels(); ++c) { + float* busChannel = targetBus->channel(c)->mutableData(); + for (size_t i = 0; i < targetBus->channel(c)->length(); ++i) { + busChannel[i] = static_cast<float>(startingValue + i); + } + } + return startingValue + targetBus->length(); +} + +// Inspect the content of AudioBus with a given set of index and value across +// channels. +bool verifyBusValueAtIndex(AudioBus* targetBus, + int index, + float expectedValue) { + for (unsigned c = 0; c < targetBus->numberOfChannels(); ++c) { + float* busChannel = targetBus->channel(c)->mutableData(); + if (busChannel[index] != expectedValue) { + LOG(ERROR) << ">> [FAIL] expected " << expectedValue << " at index " + << index << " but got " << busChannel[index] << "."; + return false; + } + } + return true; +} + +struct FIFOAction { + // The type of action; "PUSH" or "PULL". + const char* action; + // Number of frames for the operation. + const size_t numberOfFrames; +}; + +struct AudioBusSample { + // The frame index of a sample in the bus. + const size_t index; + // The value at the |index| above. + const float value; +}; + +struct FIFOTestSetup { + // Length of FIFO to be created for test case. + const size_t fifoLength; + // Channel count of FIFO to be created for test case. + const unsigned numberOfChannels; + // A list of |FIFOAction| entries to be performed in test case. + const std::vector<FIFOAction> fifoActions; +}; + +struct FIFOTestExpectedState { + // Expected read index in FIFO. + const size_t indexRead; + // Expected write index in FIFO. + const size_t indexWrite; + // Expected overflow count in FIFO. + const unsigned overflowCount; + // Expected underflow count in FIFO. + const unsigned underflowCount; + // A list of expected |AudioBusSample| entries for the FIFO bus. + const std::vector<AudioBusSample> fifoSamples; + // A list of expected |AudioBusSample| entries for the output bus. + const std::vector<AudioBusSample> outputSamples; +}; + +// The data structure for the parameterized test cases. +struct FIFOTestParam { + FIFOTestSetup setup; + FIFOTestExpectedState expectedState; +}; + +std::ostream& operator<<(std::ostream& out, const FIFOTestParam& param) { + out << "fifoLength=" << param.setup.fifoLength + << " numberOfChannels=" << param.setup.numberOfChannels; + return out; +} + +class PushPullFIFOFeatureTest : public ::testing::TestWithParam<FIFOTestParam> { +}; + +TEST_P(PushPullFIFOFeatureTest, FeatureTests) { + const FIFOTestSetup setup = GetParam().setup; + const FIFOTestExpectedState expectedState = GetParam().expectedState; + + // Create a FIFO with a specified configuration. + std::unique_ptr<PushPullFIFO> fifo = WTF::wrapUnique( + new PushPullFIFO(setup.numberOfChannels, setup.fifoLength)); + + RefPtr<AudioBus> outputBus; + + // Iterate all the scheduled push/pull actions. + size_t frameCounter = 0; + for (const auto& action : setup.fifoActions) { + if (strcmp(action.action, "PUSH") == 0) { + RefPtr<AudioBus> inputBus = + AudioBus::create(setup.numberOfChannels, action.numberOfFrames); + frameCounter = fillBusWithLinearRamp(inputBus.get(), frameCounter); + fifo->push(inputBus.get()); + LOG(INFO) << "PUSH " << action.numberOfFrames + << " frames (frameCounter=" << frameCounter << ")"; + } else { + outputBus = + AudioBus::create(setup.numberOfChannels, action.numberOfFrames); + fifo->pull(outputBus.get(), action.numberOfFrames); + LOG(INFO) << "PULL " << action.numberOfFrames << " frames"; + } + } + + // Get FIFO config data. + const PushPullFIFOStateForTest actualState = fifo->getStateForTest(); + + // Verify the read/write indexes. + EXPECT_EQ(expectedState.indexRead, actualState.indexRead); + EXPECT_EQ(expectedState.indexWrite, actualState.indexWrite); + EXPECT_EQ(expectedState.overflowCount, actualState.overflowCount); + EXPECT_EQ(expectedState.underflowCount, actualState.underflowCount); + + // Verify in-FIFO samples. + for (const auto& sample : expectedState.fifoSamples) { + EXPECT_TRUE(verifyBusValueAtIndex(fifo->bus(), sample.index, sample.value)); + } + + // Verify samples from the most recent output bus. + for (const auto& sample : expectedState.outputSamples) { + EXPECT_TRUE( + verifyBusValueAtIndex(outputBus.get(), sample.index, sample.value)); + } +} + +FIFOTestParam featureTestParams[] = { + // Test cases 0 ~ 3: Regular operation on various channel configuration. + // - Mono, Stereo, Quad, 5.1. + // - FIFO length and pull size are RQ-aligned. + {{512, 1, {{"PUSH", 128}, {"PUSH", 128}, {"PULL", 256}}}, + {256, 256, 0, 0, {{0, 0}}, {{0, 0}, {255, 255}}}}, + + {{512, 2, {{"PUSH", 128}, {"PUSH", 128}, {"PULL", 256}}}, + {256, 256, 0, 0, {{0, 0}}, {{0, 0}, {255, 255}}}}, + + {{512, 4, {{"PUSH", 128}, {"PUSH", 128}, {"PULL", 256}}}, + {256, 256, 0, 0, {{0, 0}}, {{0, 0}, {255, 255}}}}, + + {{512, 6, {{"PUSH", 128}, {"PUSH", 128}, {"PULL", 256}}}, + {256, 256, 0, 0, {{0, 0}}, {{0, 0}, {255, 255}}}}, + + // Test case 4: Pull size less than or equal to 128. + {{128, 2, {{"PUSH", 128}, {"PULL", 128}, {"PUSH", 128}, {"PULL", 64}}}, + {64, 0, 0, 0, {{64, 192}, {0, 128}}, {{0, 128}, {63, 191}}}}, + + // Test case 5: Unusual FIFO and Pull length. + // - FIFO and pull length that are not aligned to render quantum. + // - Check if the indexes are wrapping around correctly. + // - Check if the output bus starts and ends with correct values. + {{997, + 1, + { + {"PUSH", 128}, + {"PUSH", 128}, + {"PUSH", 128}, + {"PUSH", 128}, + {"PULL", 449}, + {"PUSH", 128}, + {"PUSH", 128}, + {"PUSH", 128}, + {"PUSH", 128}, + {"PULL", 449}, + }}, + // - expectedIndexRead = 898, expectedIndexWrite = 27 + // - overflowCount = 0, underflowCount = 0 + // - FIFO samples (index, expectedValue) = (898, 898), (27, 27) + // - Output bus samples (index, expectedValue) = (0, 499), (448, 897) + {898, 27, 0, 0, {{898, 898}, {27, 27}}, {{0, 449}, {448, 897}}}}, + + // Test case 6: Overflow + // - Check overflow counter. + // - After the overflow occurs, the read index must be moved to the write + // index. Thus pulled frames must not contain overwritten data. + {{512, + 3, + { + {"PUSH", 128}, + {"PUSH", 128}, + {"PUSH", 128}, + {"PUSH", 128}, + {"PUSH", 128}, + {"PULL", 256}, + }}, + // - expectedIndexRead = 384, expectedIndexWrite = 128 + // - overflowCount = 1, underflowCount = 0 + // - FIFO samples (index, expectedValue) = (384, 384), (128, 128) + // - Output bus samples (index, expectedValue) = (0, 128), (255, 383) + {384, 128, 1, 0, {{384, 384}, {128, 128}}, {{0, 128}, {255, 383}}}}, + + // Test case 7: Overflow in unusual FIFO and pull length. + // - Check overflow counter. + // - After the overflow occurs, the read index must be moved to the write + // index. Thus pulled frames must not contain overwritten data. + {{577, + 5, + { + {"PUSH", 128}, + {"PUSH", 128}, + {"PUSH", 128}, + {"PUSH", 128}, + {"PUSH", 128}, + {"PULL", 227}, + }}, + // - expectedIndexRead = 290, expectedIndexWrite = 63 + // - overflowCount = 1, underflowCount = 0 + // - FIFO samples (index, expectedValue) = (63, 63), (290, 290) + // - Output bus samples (index, expectedValue) = (0, 63), (226, 289) + {290, 63, 1, 0, {{63, 63}, {290, 290}}, {{0, 63}, {226, 289}}}}, + + // Test case 8: Underflow + // - Check underflow counter. + // - After the underflow occurs, the write index must be moved to the read + // index. Frames pulled after FIFO underflows must be zeroed. + {{512, + 7, + { + {"PUSH", 128}, + {"PUSH", 128}, + {"PUSH", 128}, + {"PULL", 384}, + {"PUSH", 128}, + {"PUSH", 128}, + {"PULL", 384}, + }}, + // - expectedIndexRead = 128, expectedIndexWrite = 128 + // - overflowCount = 0, underflowCount = 1 + // - FIFO samples (index, expectedValue) = (128, 128) + // - Output bus samples (index, expectedValue) = (0, 384), (255, 639) + // (256, 0), (383, 0) + {128, + 128, + 0, + 1, + {{128, 128}}, + {{0, 384}, {255, 639}, {256, 0}, {383, 0}}}}, + + // Test case 9: Underflow in unusual FIFO and pull length. + // - Check underflow counter. + // - After the underflow occurs, the write index must be moved to the read + // index. Frames pulled after FIFO underflows must be zeroed. + {{523, + 11, + { + {"PUSH", 128}, + {"PUSH", 128}, + {"PUSH", 128}, + {"PULL", 383}, + {"PUSH", 128}, + {"PUSH", 128}, + {"PULL", 383}, + }}, + // - expectedIndexRead = 117, expectedIndexWrite = 117 + // - overflowCount = 0, underflowCount = 1 + // - FIFO samples (index, expectedValue) = (117, 117) + // - Output bus samples (index, expectedValue) = (0, 383), (256, 639) + // (257, 0), (382, 0) + {117, + 117, + 0, + 1, + {{117, 117}}, + {{0, 383}, {256, 639}, {257, 0}, {382, 0}}}}, + + // Test case 10: Multiple pull from an empty FIFO. + // - Check underflow counter. + // - After the underflow occurs, the write index must be moved to the read + // index. Frames pulled after FIFO underflows must be zeroed. + {{1024, + 11, + { + {"PUSH", 128}, + {"PUSH", 128}, + {"PULL", 440}, + {"PULL", 440}, + {"PULL", 440}, + {"PULL", 440}, + {"PULL", 440}, + }}, + // - expectedIndexRead = 117, expectedIndexWrite = 117 + // - overflowCount = 0, underflowCount = 1 + // - FIFO samples (index, expectedValue) = (117, 117) + // - Output bus samples (index, expectedValue) = (0, 383), (256, 639) + // (257, 0), (382, 0) + {256, 256, 0, 5, {{256, 0}}, {{0, 0}, {439, 0}}}}, + + // Test case 11: Multiple pull from an empty FIFO. (zero push) + {{1024, + 11, + { + {"PULL", 144}, + {"PULL", 144}, + {"PULL", 144}, + {"PULL", 144}, + }}, + // - expectedIndexRead = 0, expectedIndexWrite = 0 + // - overflowCount = 0, underflowCount = 4 + // - FIFO samples (index, expectedValue) = (0, 0), (1023, 0) + // - Output bus samples (index, expectedValue) = (0, 0), (143, 0) + {0, 0, 0, 4, {{0, 0}, {1023, 0}}, {{0, 0}, {143, 0}}}}}; + +INSTANTIATE_TEST_CASE_P(PushPullFIFOFeatureTest, + PushPullFIFOFeatureTest, + ::testing::ValuesIn(featureTestParams)); + +} // namespace + +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/clipboard/ClipboardUtilities.h b/third_party/WebKit/Source/platform/clipboard/ClipboardUtilities.h index 5d4546b2..27b8bf7 100644 --- a/third_party/WebKit/Source/platform/clipboard/ClipboardUtilities.h +++ b/third_party/WebKit/Source/platform/clipboard/ClipboardUtilities.h
@@ -42,8 +42,6 @@ #endif PLATFORM_EXPORT void replaceNBSPWithSpace(String&); PLATFORM_EXPORT String convertURIListToURL(const String& uriList); -// FIXME: This should probably be implemented in the embedder rather than here. -PLATFORM_EXPORT void validateFilename(String& name, String& extension); } // namespace blink
diff --git a/third_party/WebKit/Source/platform/clipboard/ClipboardUtilitiesPosix.cpp b/third_party/WebKit/Source/platform/clipboard/ClipboardUtilitiesPosix.cpp deleted file mode 100644 index 90900d1e..0000000 --- a/third_party/WebKit/Source/platform/clipboard/ClipboardUtilitiesPosix.cpp +++ /dev/null
@@ -1,58 +0,0 @@ -/* - * Copyright (C) 2009 Apple Inc. All rights reserved. - * Copyright (C) 2009 Google Inc. - * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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. - */ - -#include "platform/clipboard/ClipboardUtilities.h" - -#include "wtf/text/WTFString.h" - -namespace blink { - -// On POSIX systems, the typical filename length limit is 255 character units. -// HFS+'s limit is actually 255 Unicode characters using Apple's modification of -// Normzliation Form D, but the differences aren't really worth dealing with -// here. -static const unsigned maxFilenameLength = 255; - -static bool isInvalidFileCharacter(UChar c) { - // HFS+ disallows '/' and Linux systems also disallow null. For sanity's sake - // we'll also disallow control characters. - return c < ' ' || c == 0x7F || c == '/'; -} - -void validateFilename(String& name, String& extension) { - // Remove any invalid file system characters, especially "/". - name = name.removeCharacters(&isInvalidFileCharacter); - extension = extension.removeCharacters(&isInvalidFileCharacter); - - // Remove a ridiculously-long extension. - if (extension.length() >= maxFilenameLength) - extension = String(); - - // Truncate an overly-long filename, reserving one character for a dot. - name.truncate(maxFilenameLength - extension.length() - 1); -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/platform/clipboard/ClipboardUtilitiesTest.cpp b/third_party/WebKit/Source/platform/clipboard/ClipboardUtilitiesTest.cpp deleted file mode 100644 index 4166c6426..0000000 --- a/third_party/WebKit/Source/platform/clipboard/ClipboardUtilitiesTest.cpp +++ /dev/null
@@ -1,92 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#include "platform/clipboard/ClipboardUtilities.h" - -#include "testing/gtest/include/gtest/gtest.h" -#include "wtf/StdLibExtras.h" -#include "wtf/text/WTFString.h" - -namespace blink { - -#if OS(WIN) -const char invalidCharacters[] = "\x00/\\:*?\"<>|"; -#else -const char invalidCharacters[] = - "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" - "\x7f/"; -#endif -const char longString[] = - "0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765," - "10946,17711,28657,46368," - "75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,5702887," - "9227465,14930352"; - -TEST(ClipboardUtilitiesTest, Normal) { - String name = "name"; - String extension = "ext"; - validateFilename(name, extension); - EXPECT_EQ("name", name); - EXPECT_EQ("ext", extension); -} - -TEST(ClipboardUtilitiesTest, InvalidCharacters) { - String name = "na" + - String(invalidCharacters, WTF_ARRAY_LENGTH(invalidCharacters)) + - "me"; - String extension = - "e" + String(invalidCharacters, WTF_ARRAY_LENGTH(invalidCharacters)) + - "xt"; - validateFilename(name, extension); - EXPECT_EQ("name", name); - EXPECT_EQ("ext", extension); -} - -TEST(ClipboardUtilitiesTest, ExtensionTooLong) { - String name; - String extension = String(longString) + longString; - validateFilename(name, extension); - EXPECT_EQ(String(), extension); -} - -TEST(ClipboardUtilitiesTest, NamePlusExtensionTooLong) { - String name = String(longString) + longString; - String extension = longString; - validateFilename(name, extension); - EXPECT_EQ( - "0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765," - "109", - name); - EXPECT_EQ(longString, extension); - EXPECT_EQ(254u, name.length() + extension.length()); -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/platform/clipboard/ClipboardUtilitiesWin.cpp b/third_party/WebKit/Source/platform/clipboard/ClipboardUtilitiesWin.cpp index 3b4bdf76..bb69b4bd 100644 --- a/third_party/WebKit/Source/platform/clipboard/ClipboardUtilitiesWin.cpp +++ b/third_party/WebKit/Source/platform/clipboard/ClipboardUtilitiesWin.cpp
@@ -33,15 +33,6 @@ namespace blink { -// FAT32 and NTFS both limit filenames to a maximum of 255 characters. -static const unsigned maxFilenameLength = 255; - -// Returns true if the specified character is not valid in a file name. This -// is intended for use with removeCharacters. -static bool isInvalidFileCharacter(UChar c) { - return !(PathGetCharType(c) & (GCT_LFNCHAR | GCT_SHORTCHAR)); -} - void replaceNewlinesWithWindowsStyleNewlines(String& str) { DEFINE_STATIC_LOCAL(String, windowsNewline, ("\r\n")); StringBuilder result; @@ -54,16 +45,4 @@ str = result.toString(); } -void validateFilename(String& name, String& extension) { - // Remove any invalid file system characters. - name = name.removeCharacters(&isInvalidFileCharacter); - extension = extension.removeCharacters(&isInvalidFileCharacter); - - if (extension.length() >= maxFilenameLength) - extension = String(); - - // Truncate overly-long filenames, reserving one character for a dot. - name.truncate(maxFilenameLength - extension.length() - 1); -} - } // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/Platform.cpp b/third_party/WebKit/Source/platform/exported/Platform.cpp index 9cc246e9..08cf4d5 100644 --- a/third_party/WebKit/Source/platform/exported/Platform.cpp +++ b/third_party/WebKit/Source/platform/exported/Platform.cpp
@@ -104,35 +104,6 @@ } } -void Platform::shutdown() { - ASSERT(isMainThread()); - if (s_platform->m_mainThread) { - base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( - FontCacheMemoryDumpProvider::instance()); - base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( - PartitionAllocMemoryDumpProvider::instance()); - base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( - BlinkGCMemoryDumpProvider::instance()); - base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( - MemoryCacheDumpProvider::instance()); - - ASSERT(s_gcTaskRunner); - delete s_gcTaskRunner; - s_gcTaskRunner = nullptr; - } - - // Detach the main thread before starting the shutdown sequence - // so that the main thread won't get involved in a GC during the shutdown. - ThreadState::detachMainThread(); - - ProcessHeap::shutdown(); - - WTF::shutdown(); - - s_platform->m_mainThread = nullptr; - s_platform = nullptr; -} - void Platform::setCurrentPlatformForTesting(Platform* platform) { ASSERT(platform); s_platform = platform;
diff --git a/third_party/WebKit/Source/web/WebCache.cpp b/third_party/WebKit/Source/platform/exported/WebCache.cpp similarity index 97% rename from third_party/WebKit/Source/web/WebCache.cpp rename to third_party/WebKit/Source/platform/exported/WebCache.cpp index 0bcfc6a..4c612d1 100644 --- a/third_party/WebKit/Source/web/WebCache.cpp +++ b/third_party/WebKit/Source/platform/exported/WebCache.cpp
@@ -28,7 +28,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "public/web/WebCache.h" +#include "public/platform/WebCache.h" #include "platform/loader/fetch/MemoryCache.h" @@ -62,8 +62,9 @@ if (cache) { result->capacity = cache->capacity(); result->size = cache->size(); - } else + } else { memset(result, 0, sizeof(UsageStats)); + } } void WebCache::getResourceTypeStats(ResourceTypeStats* result) { @@ -76,8 +77,9 @@ ToResourceTypeStat(stats.xslStyleSheets, result->xslStyleSheets); ToResourceTypeStat(stats.fonts, result->fonts); ToResourceTypeStat(stats.other, result->other); - } else + } else { memset(result, 0, sizeof(WebCache::ResourceTypeStats)); + } } } // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp b/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp index ec5d42c..5552310 100644 --- a/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp +++ b/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp
@@ -178,14 +178,6 @@ m_resourceResponse->setTextEncodingName(textEncodingName); } -WebString WebURLResponse::suggestedFileName() const { - return m_resourceResponse->suggestedFilename(); -} - -void WebURLResponse::setSuggestedFileName(const WebString& suggestedFileName) { - m_resourceResponse->setSuggestedFilename(suggestedFileName); -} - WebURLResponse::HTTPVersion WebURLResponse::httpVersion() const { return static_cast<HTTPVersion>(m_resourceResponse->httpVersion()); }
diff --git a/third_party/WebKit/Source/platform/fonts/Font.cpp b/third_party/WebKit/Source/platform/fonts/Font.cpp index fa6fdf6..0650ea2 100644 --- a/third_party/WebKit/Source/platform/fonts/Font.cpp +++ b/third_party/WebKit/Source/platform/fonts/Font.cpp
@@ -437,18 +437,7 @@ if (shouldSkipDrawing()) return; - if (runInfo.cachedTextBlob && runInfo.cachedTextBlob->get()) { - SkScalar boundsArray[2] = {std::get<0>(bounds), std::get<1>(bounds)}; - int numIntervals = paint.getTextBlobIntercepts( - runInfo.cachedTextBlob->get(), boundsArray, nullptr); - if (!numIntervals) - return; - DCHECK_EQ(numIntervals % 2, 0); - intercepts.resize(numIntervals / 2); - paint.getTextBlobIntercepts(runInfo.cachedTextBlob->get(), boundsArray, - reinterpret_cast<SkScalar*>(intercepts.data())); - return; - } + DCHECK(!runInfo.cachedTextBlob); GlyphBuffer glyphBuffer; // Compute skip-ink exceptions in the GlyphBuffer.
diff --git a/third_party/WebKit/Source/platform/fonts/GlyphBuffer.h b/third_party/WebKit/Source/platform/fonts/GlyphBuffer.h index 12bef29..159a226 100644 --- a/third_party/WebKit/Source/platform/fonts/GlyphBuffer.h +++ b/third_party/WebKit/Source/platform/fonts/GlyphBuffer.h
@@ -111,36 +111,6 @@ m_offsets.push_back(offset.y()); } - void reverseForSimpleRTL(float afterOffset, float totalWidth) { - ASSERT(!hasVerticalOffsets()); - - if (isEmpty()) - return; - - m_fontData.reverse(); - m_glyphs.reverse(); - - // | .. [X0 X1 .. Xn] .. | - // ^ ^ ^ - // 0 afterOffset totalWidth - // - // The input buffer is shaped using RTL advances, but since the right edge - // is unknown at that time, offsets are computed as if the advances were - // LTR. This method performs the required adjustments by reconstructing - // advances and positioning offsets in an RTL progression. - - // FIXME: we should get rid of this (idea: store negative offsets while - // shaping, and adjust the initial advance accordingly -> should - // yield correctly positioned RTL glyphs without any post-shape - // munging). - SECURITY_DCHECK(!m_offsets.isEmpty()); - for (unsigned i = 0; i + 1 < m_offsets.size(); ++i) - m_offsets[i] = totalWidth - m_offsets[i + 1]; - m_offsets.back() = totalWidth - afterOffset; - - m_offsets.reverse(); - } - void saveSkipInkExceptions() { m_skipInkExceptions = WTF::makeUnique<Vector<bool, 2048>>(); }
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h index 08c3235..7db9bcb4 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h +++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h
@@ -76,13 +76,6 @@ bool collectFallbackHintChars(const Deque<HolesQueueItem>&, Vector<UChar32>& hint) const; - void insertRunIntoShapeResult( - ShapeResult*, - std::unique_ptr<ShapeResult::RunInfo> runToInsert, - unsigned startGlyph, - unsigned numGlyphs, - hb_buffer_t*); - const UChar* m_normalizedBuffer; unsigned m_normalizedBufferLength; TextDirection m_textDirection;
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsTypes3D.h b/third_party/WebKit/Source/platform/graphics/GraphicsTypes3D.h index 8a58705..01a8bd1 100644 --- a/third_party/WebKit/Source/platform/graphics/GraphicsTypes3D.h +++ b/third_party/WebKit/Source/platform/graphics/GraphicsTypes3D.h
@@ -50,10 +50,6 @@ const unsigned GC3D_COMPRESSED_ATC_RGBA_EXPLICIT_ALPHA_AMD = 0x8C93; const unsigned GC3D_COMPRESSED_ATC_RGBA_INTERPOLATED_ALPHA_AMD = 0x87EE; -// GL_CHROMIUM_gpu_memory_buffer_image -const unsigned GC3D_MAP_CHROMIUM = 0x78F1; -const unsigned GC3D_SCANOUT_CHROMIUM = 0x78F2; - namespace blink { enum SourceDrawingBuffer { FrontBuffer, BackBuffer };
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp index 583b9c2..cb11474 100644 --- a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp +++ b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
@@ -404,9 +404,16 @@ // use N32 at this time. SkColorType colorType = useF16Workaround ? kN32_SkColorType : kRGBA_8888_SkColorType; - SkImageInfo info = - SkImageInfo::Make(rect.width(), rect.height(), colorType, alphaType, - SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named)); + + // Only use sRGB when the surface has a color space. Converting untagged + // pixels to a particular color space is not well-defined in Skia. + sk_sp<SkColorSpace> colorSpace = nullptr; + if (m_surface->colorSpace()) { + colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); + } + + SkImageInfo info = SkImageInfo::Make(rect.width(), rect.height(), colorType, + alphaType, std::move(colorSpace)); snapshot->readPixels(info, result.data(), bytesPerPixel * rect.width(), rect.x(), rect.y());
diff --git a/third_party/WebKit/Source/platform/graphics/PaintInvalidationReason.cpp b/third_party/WebKit/Source/platform/graphics/PaintInvalidationReason.cpp index 14abde1..9c3f94aa 100644 --- a/third_party/WebKit/Source/platform/graphics/PaintInvalidationReason.cpp +++ b/third_party/WebKit/Source/platform/graphics/PaintInvalidationReason.cpp
@@ -56,6 +56,8 @@ return "SVG resource change"; case PaintInvalidationBackgroundOnScrollingContentsLayer: return "background on scrolling contents layer"; + case PaintInvalidationCaret: + return "caret"; case PaintInvalidationForTesting: return "for testing"; case PaintInvalidationDelayedFull:
diff --git a/third_party/WebKit/Source/platform/graphics/PaintInvalidationReason.h b/third_party/WebKit/Source/platform/graphics/PaintInvalidationReason.h index c8ae5cc9..da6d14b 100644 --- a/third_party/WebKit/Source/platform/graphics/PaintInvalidationReason.h +++ b/third_party/WebKit/Source/platform/graphics/PaintInvalidationReason.h
@@ -34,6 +34,7 @@ PaintInvalidationLayoutObjectRemoval, PaintInvalidationSVGResourceChange, PaintInvalidationBackgroundOnScrollingContentsLayer, + PaintInvalidationCaret, PaintInvalidationForTesting, // PaintInvalidationDelayedFull means that PaintInvalidationFull is needed in // order to fully paint the content, but that painting of the object can be
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp index 85faa478..0f77c59 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
@@ -282,7 +282,7 @@ #endif FloatRect combinedClip = - geometryMapper.localToAncestorClipRect(localState, ancestorState); + geometryMapper.localToAncestorClipRect(localState, ancestorState).rect(); ccList.CreateAndAppendPairedBeginItem<cc::FloatClipDisplayItem>( gfx::RectF(combinedClip)); @@ -600,14 +600,18 @@ EffectPaintPropertyNode::root()); FloatRect paintChunkScreenVisualRect = - geometryMapper.localToAncestorVisualRect( - paintChunk.bounds, paintChunk.properties.propertyTreeState, - rootPropertyTreeState); + geometryMapper + .localToAncestorVisualRect(paintChunk.bounds, + paintChunk.properties.propertyTreeState, + rootPropertyTreeState) + .rect(); FloatRect pendingLayerScreenVisualRect = - geometryMapper.localToAncestorVisualRect( - candidatePendingLayer.bounds, candidatePendingLayer.propertyTreeState, - rootPropertyTreeState); + geometryMapper + .localToAncestorVisualRect(candidatePendingLayer.bounds, + candidatePendingLayer.propertyTreeState, + rootPropertyTreeState) + .rect(); return paintChunkScreenVisualRect.intersects(pendingLayerScreenVisualRect); }
diff --git a/third_party/WebKit/Source/platform/graphics/paint/FloatClipRect.h b/third_party/WebKit/Source/platform/graphics/paint/FloatClipRect.h new file mode 100644 index 0000000..c135f236 --- /dev/null +++ b/third_party/WebKit/Source/platform/graphics/paint/FloatClipRect.h
@@ -0,0 +1,37 @@ +// 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 FloatClipRect_h +#define FloatClipRect_h + +#include "platform/geometry/FloatRect.h" +#include "wtf/Allocator.h" + +namespace blink { + +class PLATFORM_EXPORT FloatClipRect { + USING_FAST_MALLOC(FloatClipRect); + + public: + FloatClipRect() : m_hasRadius(false) {} + + FloatClipRect(const FloatRect& rect) : m_rect(rect), m_hasRadius(false) {} + + const FloatRect& rect() const { return m_rect; } + + void intersect(const FloatRect& other) { m_rect.intersect(other); } + + bool hasRadius() const { return m_hasRadius; } + void setHasRadius(bool hasRadius) { m_hasRadius = hasRadius; } + + void setRect(const FloatRect& rect) { m_rect = rect; } + + private: + FloatRect m_rect; + bool m_hasRadius; +}; + +} // namespace blink + +#endif // FloatClipRect_h
diff --git a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp index 7ecadec8..e61aa3b 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp
@@ -9,23 +9,23 @@ namespace blink { -FloatRect GeometryMapper::sourceToDestinationVisualRect( +FloatClipRect GeometryMapper::sourceToDestinationVisualRect( const FloatRect& rect, const PropertyTreeState& sourceState, const PropertyTreeState& destinationState) { bool success = false; - FloatRect result = sourceToDestinationVisualRectInternal( + FloatClipRect result = sourceToDestinationVisualRectInternal( rect, sourceState, destinationState, success); DCHECK(success); return result; } -FloatRect GeometryMapper::sourceToDestinationVisualRectInternal( +FloatClipRect GeometryMapper::sourceToDestinationVisualRectInternal( const FloatRect& rect, const PropertyTreeState& sourceState, const PropertyTreeState& destinationState, bool& success) { - FloatRect result = localToAncestorVisualRectInternal( + FloatClipRect result = localToAncestorVisualRectInternal( rect, sourceState, destinationState, success); // Success if destinationState is an ancestor state. if (success) @@ -42,12 +42,14 @@ PropertyTreeState lcaState = destinationState; lcaState.setTransform(lcaTransform); - FloatRect lcaVisualRect = + result = localToAncestorVisualRectInternal(rect, sourceState, lcaState, success); if (!success) - return lcaVisualRect; - return ancestorToLocalRect(lcaVisualRect, lcaTransform, - destinationState.transform()); + return result; + FloatRect final = ancestorToLocalRect(result.rect(), lcaTransform, + destinationState.transform()); + result.setRect(final); + return result; } FloatRect GeometryMapper::sourceToDestinationRect( @@ -71,18 +73,18 @@ return ancestorToLocalRect(lcaRect, lcaTransform, destinationTransformNode); } -FloatRect GeometryMapper::localToAncestorVisualRect( +FloatClipRect GeometryMapper::localToAncestorVisualRect( const FloatRect& rect, const PropertyTreeState& localState, const PropertyTreeState& ancestorState) { bool success = false; - FloatRect result = localToAncestorVisualRectInternal(rect, localState, - ancestorState, success); + FloatClipRect result = localToAncestorVisualRectInternal( + rect, localState, ancestorState, success); DCHECK(success); return result; } -FloatRect GeometryMapper::localToAncestorVisualRectInternal( +FloatClipRect GeometryMapper::localToAncestorVisualRectInternal( const FloatRect& rect, const PropertyTreeState& localState, const PropertyTreeState& ancestorState, @@ -99,11 +101,11 @@ FloatRect mappedRect = transformMatrix.mapRect(rect); - const auto clipRect = + FloatClipRect clipRect = localToAncestorClipRectInternal(localState, ancestorState, success); if (success) { - mappedRect.intersect(clipRect); + clipRect.intersect(mappedRect); } else if (!RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { // On SPv1 we may fail when the paint invalidation container creates an // overflow clip (in ancestorState) which is not in localState of an @@ -114,7 +116,7 @@ success = true; } - return mappedRect; + return clipRect; } FloatRect GeometryMapper::localToAncestorRect( @@ -185,21 +187,21 @@ return *addResult.storedValue->value; } -FloatRect GeometryMapper::localToAncestorClipRect( +FloatClipRect GeometryMapper::localToAncestorClipRect( const PropertyTreeState& localState, const PropertyTreeState& ancestorState) { bool success = false; - FloatRect result = + FloatClipRect result = localToAncestorClipRectInternal(localState, ancestorState, success); DCHECK(success); return result; } -FloatRect GeometryMapper::localToAncestorClipRectInternal( +FloatClipRect GeometryMapper::localToAncestorClipRectInternal( const PropertyTreeState& localState, const PropertyTreeState& ancestorState, bool& success) { - FloatRect clip(LayoutRect::infiniteIntRect()); + FloatClipRect clip(LayoutRect::infiniteIntRect()); if (localState.clip() == ancestorState.clip()) { success = true; return clip; @@ -237,6 +239,8 @@ return clip; FloatRect mappedRect = transformMatrix.mapRect((*it)->clipRect().rect()); clip.intersect(mappedRect); + if ((*it)->clipRect().isRounded()) + clip.setHasRadius(true); clipCache.set(*it, clip); }
diff --git a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.h b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.h index 390cdc49..c0d63d6 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.h +++ b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.h
@@ -5,7 +5,7 @@ #ifndef GeometryMapper_h #define GeometryMapper_h -#include "platform/geometry/FloatRect.h" +#include "platform/graphics/paint/FloatClipRect.h" #include "platform/graphics/paint/PropertyTreeState.h" #include "platform/transforms/TransformationMatrix.h" #include "wtf/HashMap.h" @@ -17,7 +17,9 @@ // intersection of all clips between the descendant and the ancestor (*not* // including the ancestor) in the clip tree, individually transformed from // their localTransformSpace into the ancestor's localTransformSpace. -typedef HashMap<const ClipPaintPropertyNode*, FloatRect> ClipCache; +// If one of the clip that contributes to it has a border radius, the +// hasRadius() field is set to true. +typedef HashMap<const ClipPaintPropertyNode*, FloatClipRect> ClipCache; // Maps from a transform node that is a descendant of the ancestor to the // combined transform between the descendant's and the ancestor's coordinate @@ -67,7 +69,7 @@ // // DCHECK fails if the clip of |destinationState| is not an ancestor of the // clip of |sourceState|, or the inverse transform is not invertible. - FloatRect sourceToDestinationVisualRect( + FloatClipRect sourceToDestinationVisualRect( const FloatRect&, const PropertyTreeState& sourceState, const PropertyTreeState& destinationState); @@ -91,7 +93,7 @@ // DCHECK fails if any of the paint property tree nodes in // |localTransformState| are not equal to or a descendant of that in // |ancestorState|. - FloatRect localToAncestorVisualRect( + FloatClipRect localToAncestorVisualRect( const FloatRect&, const PropertyTreeState& localTransformState, const PropertyTreeState& ancestorState); @@ -130,7 +132,7 @@ // Returns the "clip visual rect" between |localTransformState| and // |ancestorState|. See above for the definition of "clip visual rect". - FloatRect localToAncestorClipRect( + FloatClipRect localToAncestorClipRect( const PropertyTreeState& localTransformState, const PropertyTreeState& ancestorState); @@ -147,13 +149,13 @@ // successful on return. See comments of the public functions for failure // conditions. - FloatRect sourceToDestinationVisualRectInternal( + FloatClipRect sourceToDestinationVisualRectInternal( const FloatRect&, const PropertyTreeState& sourceState, const PropertyTreeState& destinationState, bool& success); - FloatRect localToAncestorVisualRectInternal( + FloatClipRect localToAncestorVisualRectInternal( const FloatRect&, const PropertyTreeState& localTransformState, const PropertyTreeState& ancestorState, @@ -170,7 +172,7 @@ const TransformPaintPropertyNode* ancestorTransformNode, bool& success); - FloatRect localToAncestorClipRectInternal( + FloatClipRect localToAncestorClipRectInternal( const PropertyTreeState& localTransformState, const PropertyTreeState& ancestorState, bool& success);
diff --git a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTest.cpp b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTest.cpp index 309a7bb0..671eadd1 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTest.cpp
@@ -50,8 +50,10 @@ const PropertyTreeState& sourceState, const PropertyTreeState& destinationState, bool& success) { - return geometryMapper->localToAncestorVisualRectInternal( - rect, sourceState, destinationState, success); + return geometryMapper + ->localToAncestorVisualRectInternal(rect, sourceState, destinationState, + success) + .rect(); } FloatRect localToAncestorVisualRectInternal( @@ -59,8 +61,10 @@ const PropertyTreeState& localState, const PropertyTreeState& ancestorState, bool& success) { - return geometryMapper->localToAncestorVisualRectInternal( - rect, localState, ancestorState, success); + return geometryMapper + ->localToAncestorVisualRectInternal(rect, localState, ancestorState, + success) + .rect(); } FloatRect localToAncestorRectInternal( @@ -104,19 +108,20 @@ #define CHECK_MAPPINGS(inputRect, expectedVisualRect, expectedTransformedRect, \ expectedTransformToAncestor, \ expectedClipInAncestorSpace, localPropertyTreeState, \ - ancestorPropertyTreeState) \ + ancestorPropertyTreeState, hasRadius) \ do { \ - EXPECT_RECT_EQ( \ - expectedVisualRect, \ - geometryMapper->localToAncestorVisualRect( \ - inputRect, localPropertyTreeState, ancestorPropertyTreeState)); \ - FloatRect mappedClip = geometryMapper->localToAncestorClipRect( \ + FloatClipRect clipRect = geometryMapper->localToAncestorVisualRect( \ + inputRect, localPropertyTreeState, ancestorPropertyTreeState); \ + EXPECT_EQ(hasRadius, clipRect.hasRadius()); \ + EXPECT_RECT_EQ(expectedVisualRect, clipRect.rect()); \ + clipRect = geometryMapper->localToAncestorClipRect( \ localPropertyTreeState, ancestorPropertyTreeState); \ - EXPECT_RECT_EQ(expectedClipInAncestorSpace, mappedClip); \ - EXPECT_RECT_EQ( \ - expectedVisualRect, \ - geometryMapper->sourceToDestinationVisualRect( \ - inputRect, localPropertyTreeState, ancestorPropertyTreeState)); \ + EXPECT_EQ(hasRadius, clipRect.hasRadius()); \ + EXPECT_RECT_EQ(expectedClipInAncestorSpace, clipRect.rect()); \ + clipRect = geometryMapper->sourceToDestinationVisualRect( \ + inputRect, localPropertyTreeState, ancestorPropertyTreeState); \ + EXPECT_EQ(hasRadius, clipRect.hasRadius()); \ + EXPECT_RECT_EQ(expectedVisualRect, clipRect.rect()); \ EXPECT_RECT_EQ(expectedTransformedRect, \ geometryMapper->localToAncestorRect( \ inputRect, localPropertyTreeState.transform(), \ @@ -134,17 +139,19 @@ if (ancestorPropertyTreeState.clip() != localPropertyTreeState.clip()) { \ EXPECT_EQ(expectedClipInAncestorSpace, \ getClipCache(ancestorPropertyTreeState) \ - .get(localPropertyTreeState.clip())); \ + .get(localPropertyTreeState.clip()) \ + .rect()); \ } \ } while (false) TEST_F(GeometryMapperTest, Root) { FloatRect input(0, 0, 100, 100); + bool hasRadius = false; CHECK_MAPPINGS(input, input, input, TransformPaintPropertyNode::root()->matrix(), ClipPaintPropertyNode::root()->clipRect().rect(), - rootPropertyTreeState(), rootPropertyTreeState()); + rootPropertyTreeState(), rootPropertyTreeState(), hasRadius); } TEST_F(GeometryMapperTest, IdentityTransform) { @@ -157,9 +164,10 @@ FloatRect input(0, 0, 100, 100); + bool hasRadius = false; CHECK_MAPPINGS(input, input, input, transform->matrix(), ClipPaintPropertyNode::root()->clipRect().rect(), localState, - rootPropertyTreeState()); + rootPropertyTreeState(), hasRadius); } TEST_F(GeometryMapperTest, TranslationTransform) { @@ -174,9 +182,10 @@ FloatRect input(0, 0, 100, 100); FloatRect output = transformMatrix.mapRect(input); + bool hasRadius = false; CHECK_MAPPINGS(input, output, output, transform->matrix(), ClipPaintPropertyNode::root()->clipRect().rect(), localState, - rootPropertyTreeState()); + rootPropertyTreeState(), hasRadius); EXPECT_RECT_EQ(input, geometryMapper->ancestorToLocalRect( output, rootPropertyTreeState().transform(), @@ -197,9 +206,10 @@ FloatRect input(0, 0, 100, 100); FloatRect output = transformMatrix.mapRect(input); + bool hasRadius = false; CHECK_MAPPINGS(input, output, output, transformMatrix, ClipPaintPropertyNode::root()->clipRect().rect(), localState, - rootPropertyTreeState()); + rootPropertyTreeState(), hasRadius); } TEST_F(GeometryMapperTest, RotationAndScaleTransformWithTransformOrigin) { @@ -217,9 +227,10 @@ transformMatrix.applyTransformOrigin(50, 50, 0); FloatRect output = transformMatrix.mapRect(input); + bool hasRadius = false; CHECK_MAPPINGS(input, output, output, transformMatrix, ClipPaintPropertyNode::root()->clipRect().rect(), localState, - rootPropertyTreeState()); + rootPropertyTreeState(), hasRadius); } TEST_F(GeometryMapperTest, NestedTransforms) { @@ -242,9 +253,10 @@ TransformationMatrix final = rotateTransform * scaleTransform; FloatRect output = final.mapRect(input); + bool hasRadius = false; CHECK_MAPPINGS(input, output, output, final, ClipPaintPropertyNode::root()->clipRect().rect(), localState, - rootPropertyTreeState()); + rootPropertyTreeState(), hasRadius); // Check the cached matrix for the intermediate transform. EXPECT_EQ(rotateTransform, @@ -273,9 +285,10 @@ TransformationMatrix final = scaleTransform * translateTransform; FloatRect output = final.mapRect(input); + bool hasRadius = false; CHECK_MAPPINGS(input, output, output, final, ClipPaintPropertyNode::root()->clipRect().rect(), localState, - rootPropertyTreeState()); + rootPropertyTreeState(), hasRadius); // Check the cached matrix for the intermediate transform. EXPECT_EQ(scaleTransform, getTransformCache(rootPropertyTreeState()) @@ -305,9 +318,10 @@ FloatRect input(0, 0, 100, 100); FloatRect output = scaleTransform.mapRect(input); + bool hasRadius = false; CHECK_MAPPINGS(input, output, output, scaleTransform, ClipPaintPropertyNode::root()->clipRect().rect(), localState, - intermediateState); + intermediateState, hasRadius); } TEST_F(GeometryMapperTest, SimpleClip) { @@ -321,6 +335,7 @@ FloatRect input(0, 0, 100, 100); FloatRect output(10, 10, 50, 50); + bool hasRadius = false; CHECK_MAPPINGS(input, // Input output, // Visual rect input, // Transformed rect (not clipped). @@ -328,13 +343,42 @@ ->matrix(), // Transform matrix to ancestor space clip->clipRect().rect(), // Clip rect in ancestor space localState, - rootPropertyTreeState()); + rootPropertyTreeState(), hasRadius); +} + +TEST_F(GeometryMapperTest, RoundedClip) { + FloatRoundedRect rect(FloatRect(10, 10, 50, 50), + FloatRoundedRect::Radii(FloatSize(1, 1), FloatSize(), + FloatSize(), FloatSize())); + RefPtr<ClipPaintPropertyNode> clip = ClipPaintPropertyNode::create( + ClipPaintPropertyNode::root(), TransformPaintPropertyNode::root(), rect); + + PropertyTreeState localState = rootPropertyTreeState(); + localState.setClip(clip.get()); + + FloatRect input(0, 0, 100, 100); + FloatRect output(10, 10, 50, 50); + + bool hasRadius = true; + CHECK_MAPPINGS(input, // Input + output, // Visual rect + input, // Transformed rect (not clipped). + TransformPaintPropertyNode::root() + ->matrix(), // Transform matrix to ancestor space + clip->clipRect().rect(), // Clip rect in ancestor space + localState, + rootPropertyTreeState(), hasRadius); } TEST_F(GeometryMapperTest, TwoClips) { + FloatRoundedRect clipRect1( + FloatRect(10, 10, 30, 40), + FloatRoundedRect::Radii(FloatSize(1, 1), FloatSize(), FloatSize(), + FloatSize())); + RefPtr<ClipPaintPropertyNode> clip1 = ClipPaintPropertyNode::create( ClipPaintPropertyNode::root(), TransformPaintPropertyNode::root(), - FloatRoundedRect(10, 10, 30, 40)); + clipRect1); RefPtr<ClipPaintPropertyNode> clip2 = ClipPaintPropertyNode::create(clip1, TransformPaintPropertyNode::root(), @@ -347,6 +391,7 @@ FloatRect input(0, 0, 100, 100); FloatRect output1(10, 10, 30, 40); + bool hasRadius = true; CHECK_MAPPINGS(input, // Input output1, // Visual rect input, // Transformed rect (not clipped). @@ -354,11 +399,12 @@ ->matrix(), // Transform matrix to ancestor space clip1->clipRect().rect(), // Clip rect in ancestor space localState, - ancestorState); + ancestorState, hasRadius); ancestorState.setClip(clip1.get()); FloatRect output2(10, 10, 50, 50); + hasRadius = false; CHECK_MAPPINGS(input, // Input output2, // Visual rect input, // Transformed rect (not clipped). @@ -366,7 +412,7 @@ ->matrix(), // Transform matrix to ancestor space clip2->clipRect().rect(), // Clip rect in ancestor space localState, - ancestorState); + ancestorState, hasRadius); } TEST_F(GeometryMapperTest, ClipBeforeTransform) { @@ -389,6 +435,7 @@ output.intersect(clip->clipRect().rect()); output = rotateTransform.mapRect(output); + bool hasRadius = false; CHECK_MAPPINGS( input, // Input output, // Visual rect @@ -397,7 +444,7 @@ rotateTransform.mapRect( clip->clipRect().rect()), // Clip rect in ancestor space localState, - rootPropertyTreeState()); + rootPropertyTreeState(), hasRadius); } TEST_F(GeometryMapperTest, ClipAfterTransform) { @@ -420,13 +467,14 @@ output = rotateTransform.mapRect(output); output.intersect(clip->clipRect().rect()); + bool hasRadius = false; CHECK_MAPPINGS( input, // Input output, // Visual rect rotateTransform.mapRect(input), // Transformed rect (not clipped) rotateTransform, // Transform matrix to ancestor space clip->clipRect().rect(), // Clip rect in ancestor space - localState, rootPropertyTreeState()); + localState, rootPropertyTreeState(), hasRadius); } TEST_F(GeometryMapperTest, TwoClipsWithTransformBetween) { @@ -445,6 +493,7 @@ FloatRect input(0, 0, 100, 100); + bool hasRadius = false; { PropertyTreeState localState = rootPropertyTreeState(); localState.setClip(clip1.get()); @@ -460,7 +509,7 @@ rotateTransform.mapRect(input), // Transformed rect (not clipped) rotateTransform, // Transform matrix to ancestor space clip1->clipRect().rect(), // Clip rect in ancestor space - localState, rootPropertyTreeState()); + localState, rootPropertyTreeState(), hasRadius); } { @@ -486,7 +535,7 @@ rotateTransform.mapRect(input), // Transformed rect (not clipped) rotateTransform, // Transform matrix to ancestor space mappedClip, // Clip rect in ancestor space - localState, rootPropertyTreeState()); + localState, rootPropertyTreeState(), hasRadius); } } @@ -538,8 +587,10 @@ FloatRect expected = rotateTransform2.inverse().mapRect(rotateTransform1.mapRect(input)); - result = geometryMapper->sourceToDestinationVisualRect(input, transform1State, - transform2State); + result = geometryMapper + ->sourceToDestinationVisualRect(input, transform1State, + transform2State) + .rect(); EXPECT_RECT_EQ(expected, result); result = geometryMapper->sourceToDestinationRect(input, transform1.get(), @@ -600,8 +651,10 @@ // sourceToDestinationVisualRect ignores clip from the common ancestor to // destination. - result = geometryMapper->sourceToDestinationVisualRect( - input, transform2AndClipState, transform1State); + result = geometryMapper + ->sourceToDestinationVisualRect(input, transform2AndClipState, + transform1State) + .rect(); EXPECT_RECT_EQ(expectedClipped, result); // sourceToDestinationRect applies transforms only.
diff --git a/third_party/WebKit/Source/platform/heap/CallbackStack.cpp b/third_party/WebKit/Source/platform/heap/CallbackStack.cpp index affa37b..e3602ff6d 100644 --- a/third_party/WebKit/Source/platform/heap/CallbackStack.cpp +++ b/third_party/WebKit/Source/platform/heap/CallbackStack.cpp
@@ -25,12 +25,6 @@ CHECK(m_pooledMemory); } -void CallbackStackMemoryPool::shutdown() { - WTF::FreePages(m_pooledMemory, kBlockBytes * kPooledBlockCount); - m_pooledMemory = nullptr; - m_freeListFirst = 0; -} - CallbackStack::Item* CallbackStackMemoryPool::allocate() { MutexLocker locker(m_mutex); // Allocate from a free list if available.
diff --git a/third_party/WebKit/Source/platform/heap/CallbackStack.h b/third_party/WebKit/Source/platform/heap/CallbackStack.h index b4dfd3a..6c2619b 100644 --- a/third_party/WebKit/Source/platform/heap/CallbackStack.h +++ b/third_party/WebKit/Source/platform/heap/CallbackStack.h
@@ -127,7 +127,6 @@ static CallbackStackMemoryPool& instance(); void initialize(); - void shutdown(); CallbackStack::Item* allocate(); void free(CallbackStack::Item*);
diff --git a/third_party/WebKit/Source/platform/heap/GCInfo.cpp b/third_party/WebKit/Source/platform/heap/GCInfo.cpp index 7d2d1105c..64d1935 100644 --- a/third_party/WebKit/Source/platform/heap/GCInfo.cpp +++ b/third_party/WebKit/Source/platform/heap/GCInfo.cpp
@@ -62,11 +62,6 @@ resize(); } -void GCInfoTable::shutdown() { - WTF::Partitions::fastFree(s_gcInfoTable); - s_gcInfoTable = nullptr; -} - #if DCHECK_IS_ON() void assertObjectHasGCInfo(const void* payload, size_t gcInfoIndex) { ASSERT(HeapObjectHeader::fromPayload(payload)->checkHeader());
diff --git a/third_party/WebKit/Source/platform/heap/GCInfo.h b/third_party/WebKit/Source/platform/heap/GCInfo.h index 1d441817..c0acff8be 100644 --- a/third_party/WebKit/Source/platform/heap/GCInfo.h +++ b/third_party/WebKit/Source/platform/heap/GCInfo.h
@@ -167,7 +167,6 @@ PLATFORM_EXPORT static void ensureGCInfoIndex(const GCInfo*, size_t*); static void init(); - static void shutdown(); static size_t gcInfoIndex() { return s_gcInfoIndex; }
diff --git a/third_party/WebKit/Source/platform/heap/Heap.cpp b/third_party/WebKit/Source/platform/heap/Heap.cpp index 6de39b9..102854f 100644 --- a/third_party/WebKit/Source/platform/heap/Heap.cpp +++ b/third_party/WebKit/Source/platform/heap/Heap.cpp
@@ -101,7 +101,6 @@ } void ProcessHeap::init() { - s_shutdownComplete = false; s_totalAllocatedSpace = 0; s_totalAllocatedObjectSize = 0; s_totalMarkedObjectSize = 0; @@ -115,28 +114,12 @@ s_totalMarkedObjectSize = 0; } -void ProcessHeap::shutdown() { - ASSERT(!s_shutdownComplete); - - { - // The main thread must be the last thread that gets detached. - MutexLocker locker(ThreadHeap::allHeapsMutex()); - RELEASE_ASSERT(ThreadHeap::allHeaps().isEmpty()); - } - - CallbackStackMemoryPool::instance().shutdown(); - GCInfoTable::shutdown(); - ASSERT(ProcessHeap::totalAllocatedSpace() == 0); - s_shutdownComplete = true; -} - CrossThreadPersistentRegion& ProcessHeap::crossThreadPersistentRegion() { DEFINE_THREAD_SAFE_STATIC_LOCAL(CrossThreadPersistentRegion, persistentRegion, new CrossThreadPersistentRegion()); return persistentRegion; } -bool ProcessHeap::s_shutdownComplete = false; size_t ProcessHeap::s_totalAllocatedSpace = 0; size_t ProcessHeap::s_totalAllocatedObjectSize = 0; size_t ProcessHeap::s_totalMarkedObjectSize = 0;
diff --git a/third_party/WebKit/Source/platform/heap/Heap.h b/third_party/WebKit/Source/platform/heap/Heap.h index fd9efc0..e3a0ebb 100644 --- a/third_party/WebKit/Source/platform/heap/Heap.h +++ b/third_party/WebKit/Source/platform/heap/Heap.h
@@ -120,7 +120,6 @@ public: static void init(); - static void shutdown(); static CrossThreadPersistentRegion& crossThreadPersistentRegion(); @@ -154,7 +153,6 @@ static void resetHeapCounters(); private: - static bool s_shutdownComplete; static size_t s_totalAllocatedSpace; static size_t s_totalAllocatedObjectSize; static size_t s_totalMarkedObjectSize;
diff --git a/third_party/WebKit/Source/platform/heap/HeapPage.cpp b/third_party/WebKit/Source/platform/heap/HeapPage.cpp index 79c74b5..acb4f92 100644 --- a/third_party/WebKit/Source/platform/heap/HeapPage.cpp +++ b/third_party/WebKit/Source/platform/heap/HeapPage.cpp
@@ -179,27 +179,8 @@ page->invalidateObjectStartBitmap(); } - // If a new GC is requested before this thread got around to sweep, - // ie. due to the thread doing a long running operation, we clear - // the mark bits and mark any of the dead objects as dead. The latter - // is used to ensure the next GC marking does not trace already dead - // objects. If we trace a dead object we could end up tracing into - // garbage or the middle of another object via the newly conservatively - // found object. - BasePage* previousPage = nullptr; - for (BasePage *page = m_firstUnsweptPage; page; - previousPage = page, page = page->next()) { - page->makeConsistentForGC(); - ASSERT(!page->hasBeenSwept()); - page->invalidateObjectStartBitmap(); - } - if (previousPage) { - ASSERT(m_firstUnsweptPage); - previousPage->m_next = m_firstPage; - m_firstPage = m_firstUnsweptPage; - m_firstUnsweptPage = nullptr; - } - ASSERT(!m_firstUnsweptPage); + // We should not start a new GC until we finish sweeping in the current GC. + CHECK(!m_firstUnsweptPage); HeapCompact* heapCompactor = getThreadState()->heap().compaction(); if (!heapCompactor->isCompactingArena(arenaIndex())) @@ -1525,31 +1506,6 @@ #endif } -void NormalPage::makeConsistentForGC() { - size_t markedObjectSize = 0; - for (Address headerAddress = payload(); headerAddress < payloadEnd();) { - HeapObjectHeader* header = - reinterpret_cast<HeapObjectHeader*>(headerAddress); - ASSERT(header->size() < blinkPagePayloadSize()); - // Check if a free list entry first since we cannot call - // isMarked on a free list entry. - if (header->isFree()) { - headerAddress += header->size(); - continue; - } - if (header->isMarked()) { - header->unmark(); - markedObjectSize += header->size(); - } else { - header->markDead(); - } - headerAddress += header->size(); - } - if (markedObjectSize) - arenaForNormalPage()->getThreadState()->increaseMarkedObjectSize( - markedObjectSize); -} - void NormalPage::makeConsistentForMutator() { Address startOfGap = payload(); NormalPageArena* normalArena = arenaForNormalPage(); @@ -1703,7 +1659,7 @@ DCHECK(contains(address)); #endif HeapObjectHeader* header = findHeaderFromAddress(address); - if (!header || header->isDead()) + if (!header) return; markPointer(visitor, header); } @@ -1714,7 +1670,7 @@ MarkedPointerCallbackForTesting callback) { DCHECK(contains(address)); HeapObjectHeader* header = findHeaderFromAddress(address); - if (!header || header->isDead()) + if (!header) return; if (!callback(header)) markPointer(visitor, header); @@ -1816,16 +1772,6 @@ arena()->getThreadState()->increaseMarkedObjectSize(size()); } -void LargeObjectPage::makeConsistentForGC() { - HeapObjectHeader* header = heapObjectHeader(); - if (header->isMarked()) { - header->unmark(); - arena()->getThreadState()->increaseMarkedObjectSize(size()); - } else { - header->markDead(); - } -} - void LargeObjectPage::makeConsistentForMutator() { HeapObjectHeader* header = heapObjectHeader(); if (header->isMarked()) @@ -1844,7 +1790,7 @@ #if DCHECK_IS_ON() DCHECK(contains(address)); #endif - if (!containedInObjectPayload(address) || heapObjectHeader()->isDead()) + if (!containedInObjectPayload(address)) return; markPointer(visitor, heapObjectHeader()); } @@ -1855,7 +1801,7 @@ Address address, MarkedPointerCallbackForTesting callback) { DCHECK(contains(address)); - if (!containedInObjectPayload(address) || heapObjectHeader()->isDead()) + if (!containedInObjectPayload(address)) return; if (!callback(heapObjectHeader())) markPointer(visitor, heapObjectHeader());
diff --git a/third_party/WebKit/Source/platform/heap/HeapPage.h b/third_party/WebKit/Source/platform/heap/HeapPage.h index 233d8de..6340c54 100644 --- a/third_party/WebKit/Source/platform/heap/HeapPage.h +++ b/third_party/WebKit/Source/platform/heap/HeapPage.h
@@ -157,12 +157,8 @@ const size_t headerSizeMask = (static_cast<size_t>((1 << 14) - 1)) << 3; const size_t headerMarkBitMask = 1; const size_t headerFreedBitMask = 2; -// The dead bit is used for objects that have gone through a GC marking, but did -// not get swept before a new GC started. In that case we set the dead bit on -// objects that were not marked in the previous GC to ensure we are not tracing -// them via a conservatively found pointer. Tracing dead objects could lead to -// tracing of already finalized objects in another thread's heap which is a -// use-after-free situation. +// TODO(haraken): Remove the dead bit. It is used only by a header of +// a promptly freed object. const size_t headerDeadBitMask = 4; // On free-list entries we reuse the dead bit to distinguish a normal free-list // entry from one that has been promptly freed. @@ -232,8 +228,6 @@ bool isMarked() const; void mark(); void unmark(); - void markDead(); - bool isDead() const; Address payload(); size_t payloadSize(); @@ -399,7 +393,6 @@ virtual bool isEmpty() = 0; virtual void removeFromHeap() = 0; virtual void sweep() = 0; - virtual void makeConsistentForGC() = 0; virtual void makeConsistentForMutator() = 0; virtual void invalidateObjectStartBitmap() = 0; @@ -492,7 +485,6 @@ bool isEmpty() override; void removeFromHeap() override; void sweep() override; - void makeConsistentForGC() override; void makeConsistentForMutator() override; void invalidateObjectStartBitmap() override { m_objectStartBitMapComputed = false; @@ -577,7 +569,6 @@ bool isEmpty() override; void removeFromHeap() override; void sweep() override; - void makeConsistentForGC() override; void makeConsistentForMutator() override; void invalidateObjectStartBitmap() override {} #if defined(ADDRESS_SANITIZER) @@ -941,20 +932,6 @@ m_encoded &= ~headerMarkBitMask; } -NO_SANITIZE_ADDRESS inline bool HeapObjectHeader::isDead() const { - ASSERT(checkHeader()); - return m_encoded & headerDeadBitMask; -} - -NO_SANITIZE_ADDRESS inline void HeapObjectHeader::markDead() { - // A Dead state should not happen in a per-thread heap world. - // TODO(haraken): Remove code to handle the Dead state. - CHECK(false); - ASSERT(checkHeader()); - ASSERT(!isMarked()); - m_encoded |= headerDeadBitMask; -} - inline Address NormalPageArena::allocateObject(size_t allocationSize, size_t gcInfoIndex) { if (LIKELY(allocationSize <= m_remainingAllocationSize)) {
diff --git a/third_party/WebKit/Source/platform/heap/Persistent.h b/third_party/WebKit/Source/platform/heap/Persistent.h index 3fe022c..e9a0851 100644 --- a/third_party/WebKit/Source/platform/heap/Persistent.h +++ b/third_party/WebKit/Source/platform/heap/Persistent.h
@@ -231,14 +231,6 @@ } void uninitialize() { - // TODO(haraken): This is a short-term hack to prevent use-after-frees - // during a shutdown sequence. - // 1) blink::shutdown() frees the underlying storage for persistent nodes. - // 2) ~MessageLoop() destructs some Chromium-side objects that hold - // Persistent. It touches the underlying storage and crashes. - if (WTF::isShutdown()) - return; - if (crossThreadnessConfiguration == CrossThreadPersistentConfiguration) { if (acquireLoad(reinterpret_cast<void* volatile*>(&m_persistentNode))) ProcessHeap::crossThreadPersistentRegion().freePersistentNode(
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.cpp b/third_party/WebKit/Source/platform/heap/ThreadState.cpp index a656dfec..d254637 100644 --- a/third_party/WebKit/Source/platform/heap/ThreadState.cpp +++ b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
@@ -198,13 +198,11 @@ } void ThreadState::attachMainThread() { - RELEASE_ASSERT(!ProcessHeap::s_shutdownComplete); s_threadSpecific = new WTF::ThreadSpecific<ThreadState*>(); new (s_mainThreadStateStorage) ThreadState(); } void ThreadState::attachCurrentThread() { - RELEASE_ASSERT(!ProcessHeap::s_shutdownComplete); new ThreadState(); } @@ -263,33 +261,6 @@ cleanupPages(); } -void ThreadState::cleanupMainThread() { - ASSERT(isMainThread()); - - releaseStaticPersistentNodes(); - - // Finish sweeping before shutting down V8. Otherwise, some destructor - // may access V8 and cause crashes. - completeSweep(); - - // It is unsafe to trigger GCs after this point because some - // destructor may access already-detached V8 and cause crashes. - // Also it is useless. So we forbid GCs. - enterGCForbiddenScope(); -} - -void ThreadState::detachMainThread() { - // Enter a safe point before trying to acquire threadAttachMutex - // to avoid dead lock if another thread is preparing for GC, has acquired - // threadAttachMutex and waiting for other threads to pause or reach a - // safepoint. - ThreadState* state = mainThreadState(); - ASSERT(!state->isSweepingInProgress()); - - state->heap().detach(state); - state->~ThreadState(); -} - void ThreadState::detachCurrentThread() { ThreadState* state = current(); state->heap().detach(state);
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.h b/third_party/WebKit/Source/platform/heap/ThreadState.h index 8769d2b..df38bec 100644 --- a/third_party/WebKit/Source/platform/heap/ThreadState.h +++ b/third_party/WebKit/Source/platform/heap/ThreadState.h
@@ -168,8 +168,6 @@ bool isTerminating() { return m_isTerminating; } static void attachMainThread(); - static void detachMainThread(); - void cleanupMainThread(); // Associate ThreadState object with the current thread. After this // call thread can start using the garbage collected heap infrastructure.
diff --git a/third_party/WebKit/Source/platform/loader/fetch/FetchContext.cpp b/third_party/WebKit/Source/platform/loader/fetch/FetchContext.cpp index c6ec50cb..5f29873 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/FetchContext.cpp +++ b/third_party/WebKit/Source/platform/loader/fetch/FetchContext.cpp
@@ -92,7 +92,7 @@ ResourceRequest&, Resource::Type, const AtomicString& fetchInitiatorName, - bool) {} + V8ActivityLoggingPolicy) {} void FetchContext::didLoadResource(Resource*) {}
diff --git a/third_party/WebKit/Source/platform/loader/fetch/FetchContext.h b/third_party/WebKit/Source/platform/loader/fetch/FetchContext.h index ffc6869..1c42354a 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/FetchContext.h +++ b/third_party/WebKit/Source/platform/loader/fetch/FetchContext.h
@@ -124,23 +124,23 @@ virtual bool shouldLoadNewResource(Resource::Type) const { return false; } // Called when a resource load is first requested, which may not be when the // load actually begins. - // TODO(toyoshim): Consider to use enum. See https://crbug.com/675883. + enum class V8ActivityLoggingPolicy { SuppressLogging, Log }; virtual void willStartLoadingResource(unsigned long identifier, ResourceRequest&, Resource::Type, const AtomicString& fetchInitiatorName, - bool forPreload); + V8ActivityLoggingPolicy); virtual void didLoadResource(Resource*); virtual void addResourceTiming(const ResourceTimingInfo&); virtual bool allowImage(bool, const KURL&) const { return false; } - // TODO(toyoshim): Consider to use enum. See https://crbug.com/675883. + enum class SecurityViolationReportingPolicy { SuppressReporting, Report }; virtual ResourceRequestBlockedReason canRequest( Resource::Type, const ResourceRequest&, const KURL&, const ResourceLoaderOptions&, - bool forPreload, + SecurityViolationReportingPolicy, FetchRequest::OriginRestriction) const { return ResourceRequestBlockedReason::Other; }
diff --git a/third_party/WebKit/Source/platform/loader/fetch/FetchRequest.cpp b/third_party/WebKit/Source/platform/loader/fetch/FetchRequest.cpp index 0200a64..0c5e18e 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/FetchRequest.cpp +++ b/third_party/WebKit/Source/platform/loader/fetch/FetchRequest.cpp
@@ -39,7 +39,7 @@ : m_resourceRequest(resourceRequest), m_charset(charset), m_options(ResourceFetcher::defaultResourceOptions()), - m_forPreload(false), + m_speculativePreload(false), m_linkPreload(false), m_preloadDiscoveryTime(0.0), m_defer(NoDefer), @@ -53,7 +53,7 @@ const ResourceLoaderOptions& options) : m_resourceRequest(resourceRequest), m_options(options), - m_forPreload(false), + m_speculativePreload(false), m_linkPreload(false), m_preloadDiscoveryTime(0.0), m_defer(NoDefer), @@ -67,7 +67,7 @@ const FetchInitiatorInfo& initiator) : m_resourceRequest(resourceRequest), m_options(ResourceFetcher::defaultResourceOptions()), - m_forPreload(false), + m_speculativePreload(false), m_linkPreload(false), m_preloadDiscoveryTime(0.0), m_defer(NoDefer), @@ -132,8 +132,9 @@ } } -void FetchRequest::setForPreload(bool forPreload, double discoveryTime) { - m_forPreload = forPreload; +void FetchRequest::setSpeculativePreload(bool speculativePreload, + double discoveryTime) { + m_speculativePreload = speculativePreload; m_preloadDiscoveryTime = discoveryTime; }
diff --git a/third_party/WebKit/Source/platform/loader/fetch/FetchRequest.h b/third_party/WebKit/Source/platform/loader/fetch/FetchRequest.h index a2dea73..44f7213d7 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/FetchRequest.h +++ b/third_party/WebKit/Source/platform/loader/fetch/FetchRequest.h
@@ -57,8 +57,8 @@ }; // TODO(toyoshim): Consider to define an enum for preload options, and use it // instead of bool in this class, FrameFetchContext, and so on. If it is - // reasonable, we try merging m_forPreload and m_linkPreload into one enum - // type. See https://crbug.com/675883. + // reasonable, we try merging m_speculativePreload and m_linkPreload into one + // enum type. See https://crbug.com/675883. struct ResourceWidth { DISALLOW_NEW(); @@ -96,12 +96,12 @@ return m_clientHintPreferences; } - bool forPreload() const { return m_forPreload; } - void setForPreload(bool forPreload, double discoveryTime = 0); + bool isSpeculativePreload() const { return m_speculativePreload; } + void setSpeculativePreload(bool speculativePreload, double discoveryTime = 0); double preloadDiscoveryTime() { return m_preloadDiscoveryTime; } - bool isLinkPreload() { return m_linkPreload; } + bool isLinkPreload() const { return m_linkPreload; } void setLinkPreload(bool isLinkPreload) { m_linkPreload = isLinkPreload; } void setContentSecurityCheck( @@ -152,7 +152,7 @@ ResourceRequest m_resourceRequest; String m_charset; ResourceLoaderOptions m_options; - bool m_forPreload; + bool m_speculativePreload; bool m_linkPreload; double m_preloadDiscoveryTime; DeferOption m_defer;
diff --git a/third_party/WebKit/Source/platform/loader/fetch/MemoryCacheCorrectnessTest.cpp b/third_party/WebKit/Source/platform/loader/fetch/MemoryCacheCorrectnessTest.cpp index 66acc34..d641f94 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/MemoryCacheCorrectnessTest.cpp +++ b/third_party/WebKit/Source/platform/loader/fetch/MemoryCacheCorrectnessTest.cpp
@@ -73,7 +73,7 @@ request.setURL(KURL(ParsedURLString, kResourceURL)); MockResource* resource = MockResource::create(request); resource->setResponse(ResourceResponse(KURL(ParsedURLString, kResourceURL), - "text/html", 0, nullAtom, String())); + "text/html", 0, nullAtom)); resource->finish(); memoryCache()->add(resource);
diff --git a/third_party/WebKit/Source/platform/loader/fetch/MockFetchContext.h b/third_party/WebKit/Source/platform/loader/fetch/MockFetchContext.h index 6a7efaf7..dc7817a 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/MockFetchContext.h +++ b/third_party/WebKit/Source/platform/loader/fetch/MockFetchContext.h
@@ -53,7 +53,7 @@ const ResourceRequest&, const KURL&, const ResourceLoaderOptions&, - bool forPreload, + SecurityViolationReportingPolicy, FetchRequest::OriginRestriction) const override { return ResourceRequestBlockedReason::None; }
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp index da7d65d..5f21df7 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp +++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp
@@ -157,7 +157,7 @@ const ResourceRequest& resourceRequest, ResourcePriority::VisibilityStatus visibility, FetchRequest::DeferOption deferOption, - bool forPreload) { + bool speculativePreload) { ResourceLoadPriority priority = typeToPriority(type); // Visible resources (images in practice) get a boost to High priority. @@ -180,10 +180,13 @@ // typeToPriority) // Async/Defer: Low Priority (applies to both preload and parser-inserted) // Preload late in document: Medium - if (FetchRequest::LazyLoad == deferOption) + if (FetchRequest::LazyLoad == deferOption) { priority = ResourceLoadPriorityLow; - else if (forPreload && m_imageFetched) + } else if (speculativePreload && m_imageFetched) { + // Speculative preload is used as a signal for scripts at the bottom of + // the document. priority = ResourceLoadPriorityMedium; + } } else if (FetchRequest::LazyLoad == deferOption) { priority = ResourceLoadPriorityVeryLow; } @@ -276,8 +279,9 @@ bool ResourceFetcher::resourceNeedsLoad(Resource* resource, const FetchRequest& request, RevalidationPolicy policy) { - // Defer a font load until it is actually needed unless this is a preload. - if (resource->getType() == Resource::Font && !request.forPreload()) + // Defer a font load until it is actually needed unless this is a link + // preload. + if (resource->getType() == Resource::Font && !request.isLinkPreload()) return false; if (resource->isImage() && shouldDeferImageLoad(resource->url())) return false; @@ -382,7 +386,7 @@ data = archiveResource->data(); } - ResourceResponse response(url, mimetype, data->size(), charset, String()); + ResourceResponse response(url, mimetype, data->size(), charset); response.setHTTPStatusCode(200); response.setHTTPStatusText("OK"); @@ -415,15 +419,15 @@ return resource; } -void ResourceFetcher::moveCachedNonBlockingResourceToBlocking( +void ResourceFetcher::makePreloadedResourceBlockOnloadIfNeeded( Resource* resource, const FetchRequest& request) { // TODO(yoav): Test that non-blocking resources (video/audio/track) continue // to not-block even after being preloaded and discovered. if (resource && resource->loader() && resource->isLoadEventBlockingResourceType() && - m_nonBlockingLoaders.contains(resource->loader()) && - resource->isLinkPreload() && !request.forPreload()) { + resource->isLinkPreload() && !request.isLinkPreload() && + m_nonBlockingLoaders.contains(resource->loader())) { m_nonBlockingLoaders.remove(resource->loader()); m_loaders.insert(resource->loader()); } @@ -437,7 +441,7 @@ if (isStaticData) return; - if (request.forPreload()) { + if (request.isSpeculativePreload() || request.isLinkPreload()) { DEFINE_RESOURCE_HISTOGRAM("Preload."); } else { DEFINE_RESOURCE_HISTOGRAM(""); @@ -474,7 +478,7 @@ resourceRequest.setPriority(computeLoadPriority( factory.type(), request.resourceRequest(), ResourcePriority::NotVisible, - request.defer(), request.forPreload())); + request.defer(), request.isSpeculativePreload())); initializeResourceRequest(resourceRequest, factory.type(), request.defer()); network_instrumentation::resourcePrioritySet(identifier, resourceRequest.priority()); @@ -482,7 +486,12 @@ blockedReason = context().canRequest( factory.type(), resourceRequest, MemoryCache::removeFragmentIdentifierIfNeeded(request.url()), - request.options(), request.forPreload(), request.getOriginRestriction()); + request.options(), + /* Don't send security violation reports for speculative preloads */ + request.isSpeculativePreload() + ? FetchContext::SecurityViolationReportingPolicy::SuppressReporting + : FetchContext::SecurityViolationReportingPolicy::Report, + request.getOriginRestriction()); if (blockedReason != ResourceRequestBlockedReason::None) { DCHECK(!substituteData.forceSynchronousLoad()); return Block; @@ -490,7 +499,10 @@ context().willStartLoadingResource( identifier, resourceRequest, factory.type(), - request.options().initiatorInfo.name, request.forPreload()); + request.options().initiatorInfo.name, + (request.isSpeculativePreload() + ? FetchContext::V8ActivityLoggingPolicy::SuppressLogging + : FetchContext::V8ActivityLoggingPolicy::Log)); if (!request.url().isValid()) return Abort; @@ -539,9 +551,9 @@ memoryCache()->resourceForURL(request.url(), getCacheIdentifier()); } - // See if we can use an existing resource from the cache. If so, we need to - // move it to be load blocking. - moveCachedNonBlockingResourceToBlocking(resource, request); + // If we got a preloaded resource from the cache for a non-preload request, + // we may need to make it block the onload event. + makePreloadedResourceBlockOnloadIfNeeded(resource, request); const RevalidationPolicy policy = determineRevalidationPolicy( factory.type(), request, resource, isStaticData); @@ -568,7 +580,8 @@ if (!resource) return nullptr; if (resource->getType() != factory.type()) { - DCHECK(request.forPreload()); + DCHECK(request.isSpeculativePreload() || request.isLinkPreload()); + // TODO(yoav): What's the scenario where this can actually happen? return nullptr; } @@ -578,7 +591,9 @@ if (policy != Use) resource->setIdentifier(identifier); - if (!request.forPreload() || policy != Use) { + // TODO(yoav): It is not clear why preloads are exempt from this check. Can we + // remove the exemption? + if (!request.isSpeculativePreload() || policy != Use) { // When issuing another request for a resource that is already in-flight // make sure to not demote the priority of the in-flight request. If the new // request isn't at the same priority as the in-flight request, only allow @@ -587,6 +602,8 @@ // lower priority). if (resourceRequest.priority() > resource->resourceRequest().priority()) resource->didChangePriority(resourceRequest.priority(), 0); + // TODO(yoav): I'd expect the stated scenario to not go here, as its policy + // would be Use. } // If only the fragment identifiers differ, it is the same resource. @@ -708,7 +725,7 @@ Resource* resource = factory.create(request.resourceRequest(), request.options(), charset); resource->setLinkPreload(request.isLinkPreload()); - if (request.forPreload()) { + if (request.isSpeculativePreload()) { resource->setPreloadDiscoveryTime(request.preloadDiscoveryTime()); } resource->setCacheIdentifier(cacheIdentifier); @@ -811,7 +828,7 @@ return Reload; // We already have a preload going for this URL. - if (fetchRequest.forPreload() && existingResource->isPreloaded()) + if (fetchRequest.isSpeculativePreload() && existingResource->isPreloaded()) return Use; // If the same URL has been loaded as a different type, we need to reload. @@ -1479,7 +1496,8 @@ FetchRequest request(resourceRequest, initiatorName, resource->options()); context().canRequest(resource->getType(), resource->lastResourceRequest(), resource->lastResourceRequest().url(), request.options(), - false, request.getOriginRestriction()); + FetchContext::SecurityViolationReportingPolicy::Report, + request.getOriginRestriction()); requestLoadStarted(resource->identifier(), resource, request, ResourceLoadingFromCache); }
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.h b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.h index 49a1456..8e47ccb2 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.h +++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.h
@@ -169,7 +169,7 @@ const ResourceRequest&, ResourcePriority::VisibilityStatus, FetchRequest::DeferOption = FetchRequest::NoDefer, - bool forPreload = false); + bool speculativePreload = false); enum PrepareRequestResult { Abort, Continue, Block }; @@ -193,7 +193,7 @@ Resource* existingResource, bool isStaticData) const; - void moveCachedNonBlockingResourceToBlocking(Resource*, const FetchRequest&); + void makePreloadedResourceBlockOnloadIfNeeded(Resource*, const FetchRequest&); void moveResourceLoaderToNonBlocking(ResourceLoader*); void removeResourceLoader(ResourceLoader*); void handleLoadCompletion(Resource*);
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.cpp index 510afc9..488ee42 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.cpp +++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.cpp
@@ -172,7 +172,11 @@ if (!isManualRedirectFetchRequest(m_resource->resourceRequest())) { ResourceRequestBlockedReason blockedReason = context().canRequest( m_resource->getType(), newRequest, newRequest.url(), - m_resource->options(), m_resource->isUnusedPreload(), + m_resource->options(), + /* Don't send security violation reports for unused preloads */ + (m_resource->isUnusedPreload() + ? FetchContext::SecurityViolationReportingPolicy::SuppressReporting + : FetchContext::SecurityViolationReportingPolicy::Report), FetchRequest::UseDefaultOriginRestrictionForType); if (blockedReason != ResourceRequestBlockedReason::None) { cancelForRedirectAccessCheckError(newRequest.url(), blockedReason); @@ -258,11 +262,15 @@ Resource* resource, const ResourceResponse& response) const { // Redirects can change the response URL different from one of request. - bool forPreload = resource->isUnusedPreload(); - ResourceRequestBlockedReason blockedReason = - context().canRequest(resource->getType(), resource->resourceRequest(), - response.url(), resource->options(), forPreload, - FetchRequest::UseDefaultOriginRestrictionForType); + bool unusedPreload = resource->isUnusedPreload(); + ResourceRequestBlockedReason blockedReason = context().canRequest( + resource->getType(), resource->resourceRequest(), response.url(), + resource->options(), + /* Don't send security violation reports for unused preloads */ + (unusedPreload + ? FetchContext::SecurityViolationReportingPolicy::SuppressReporting + : FetchContext::SecurityViolationReportingPolicy::Report), + FetchRequest::UseDefaultOriginRestrictionForType); if (blockedReason != ResourceRequestBlockedReason::None) return blockedReason; @@ -286,7 +294,7 @@ sourceOrigin); if (corsStatus != CrossOriginAccessControl::kAccessAllowed) { resource->setCORSFailed(); - if (!forPreload) { + if (!unusedPreload) { String resourceType = Resource::resourceTypeToString( resource->getType(), resource->options().initiatorInfo.name); StringBuilder builder;
diff --git a/third_party/WebKit/Source/platform/mojo/Geometry.typemap b/third_party/WebKit/Source/platform/mojo/Geometry.typemap index a97b6f491d..3e1e17d 100644 --- a/third_party/WebKit/Source/platform/mojo/Geometry.typemap +++ b/third_party/WebKit/Source/platform/mojo/Geometry.typemap
@@ -4,8 +4,10 @@ mojom = "//ui/gfx/geometry/mojo/geometry.mojom" public_headers = [ "//third_party/WebKit/public/platform/WebSize.h" ] -traits_headers = - [ "//third_party/WebKit/Source/platform/mojo/GeometryStructTraits.h" ] +traits_headers = [ + "//third_party/WebKit/Source/platform/mojo/GeometryStructTraits.h", + "//ui/gfx/geometry/mojo/geometry_struct_traits.h", +] # Note: consumers of this typemap must themselves depend on platform. deps = [
diff --git a/third_party/WebKit/Source/platform/mojo/OWNERS b/third_party/WebKit/Source/platform/mojo/OWNERS index 551ce2f2f..e482ac73 100644 --- a/third_party/WebKit/Source/platform/mojo/OWNERS +++ b/third_party/WebKit/Source/platform/mojo/OWNERS
@@ -1,2 +1,4 @@ per-file *StructTraits*.*=set noparent per-file *StructTraits*.*=file://ipc/SECURITY_OWNERS +per-file *.typemap=set noparent +per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/third_party/WebKit/Source/platform/network/ResourceResponse.cpp b/third_party/WebKit/Source/platform/network/ResourceResponse.cpp index d627853..79b9a01 100644 --- a/third_party/WebKit/Source/platform/network/ResourceResponse.cpp +++ b/third_party/WebKit/Source/platform/network/ResourceResponse.cpp
@@ -26,9 +26,11 @@ #include "platform/network/ResourceResponse.h" +#include "platform/HTTPNames.h" #include "wtf/CurrentTime.h" #include "wtf/PtrUtil.h" #include "wtf/StdLibExtras.h" + #include <memory> namespace blink { @@ -108,13 +110,11 @@ ResourceResponse::ResourceResponse(const KURL& url, const AtomicString& mimeType, long long expectedLength, - const AtomicString& textEncodingName, - const String& filename) + const AtomicString& textEncodingName) : m_url(url), m_mimeType(mimeType), m_expectedContentLength(expectedLength), m_textEncodingName(textEncodingName), - m_suggestedFilename(filename), m_httpStatusCode(0), m_lastModifiedDate(0), m_wasCached(false), @@ -154,7 +154,6 @@ setMimeType(AtomicString(data->m_mimeType)); setExpectedContentLength(data->m_expectedContentLength); setTextEncodingName(AtomicString(data->m_textEncodingName)); - setSuggestedFilename(data->m_suggestedFilename); setHTTPStatusCode(data->m_httpStatusCode); setHTTPStatusText(AtomicString(data->m_httpStatusText)); @@ -219,7 +218,6 @@ data->m_mimeType = mimeType().getString().isolatedCopy(); data->m_expectedContentLength = expectedContentLength(); data->m_textEncodingName = textEncodingName().getString().isolatedCopy(); - data->m_suggestedFilename = suggestedFilename().isolatedCopy(); data->m_httpStatusCode = httpStatusCode(); data->m_httpStatusText = httpStatusText().getString().isolatedCopy(); data->m_httpHeaders = httpHeaderFields().copyData(); @@ -332,19 +330,6 @@ m_textEncodingName = encodingName; } -// FIXME should compute this on the fly -const String& ResourceResponse::suggestedFilename() const { - return m_suggestedFilename; -} - -void ResourceResponse::setSuggestedFilename(const String& suggestedName) { - m_isNull = false; - - // FIXME: Suggested file name is calculated based on other headers. There - // should not be a setter for it. - m_suggestedFilename = suggestedName; -} - int ResourceResponse::httpStatusCode() const { return m_httpStatusCode; } @@ -544,9 +529,8 @@ } bool ResourceResponse::isAttachment() const { - static const char headerName[] = "content-disposition"; static const char attachmentString[] = "attachment"; - String value = m_httpHeaderFields.get(headerName); + String value = m_httpHeaderFields.get(HTTPNames::Content_Disposition); size_t loc = value.find(';'); if (loc != kNotFound) value = value.left(loc); @@ -652,8 +636,6 @@ return false; if (a.textEncodingName() != b.textEncodingName()) return false; - if (a.suggestedFilename() != b.suggestedFilename()) - return false; if (a.httpStatusCode() != b.httpStatusCode()) return false; if (a.httpStatusText() != b.httpStatusText())
diff --git a/third_party/WebKit/Source/platform/network/ResourceResponse.h b/third_party/WebKit/Source/platform/network/ResourceResponse.h index bb0f21a27..fe72dc8 100644 --- a/third_party/WebKit/Source/platform/network/ResourceResponse.h +++ b/third_party/WebKit/Source/platform/network/ResourceResponse.h
@@ -138,8 +138,7 @@ ResourceResponse(const KURL&, const AtomicString& mimeType, long long expectedLength, - const AtomicString& textEncodingName, - const String& filename); + const AtomicString& textEncodingName); ResourceResponse(const ResourceResponse&); ResourceResponse& operator=(const ResourceResponse&); @@ -173,13 +172,6 @@ const AtomicString& textEncodingName() const; void setTextEncodingName(const AtomicString&); - // FIXME: Should compute this on the fly. - // There should not be a setter exposed, as suggested file name is determined - // based on other headers in a manner that WebCore does not necessarily know - // about. - const String& suggestedFilename() const; - void setSuggestedFilename(const String&); - int httpStatusCode() const; void setHTTPStatusCode(int); @@ -397,7 +389,6 @@ AtomicString m_mimeType; long long m_expectedContentLength; AtomicString m_textEncodingName; - String m_suggestedFilename; int m_httpStatusCode; AtomicString m_httpStatusText; HTTPHeaderMap m_httpHeaderFields; @@ -545,7 +536,6 @@ String m_mimeType; long long m_expectedContentLength; String m_textEncodingName; - String m_suggestedFilename; int m_httpStatusCode; String m_httpStatusText; std::unique_ptr<CrossThreadHTTPHeaderMapData> m_httpHeaders;
diff --git a/third_party/WebKit/Source/platform/text/TextBreakIterator.cpp b/third_party/WebKit/Source/platform/text/TextBreakIterator.cpp index 438911f..a908f0a 100644 --- a/third_party/WebKit/Source/platform/text/TextBreakIterator.cpp +++ b/third_party/WebKit/Source/platform/text/TextBreakIterator.cpp
@@ -255,12 +255,9 @@ int len = static_cast<int>(length); int nextBreak = -1; - CharacterType lastLastCh = - pos > 1 ? str[pos - 2] : static_cast<CharacterType>( - lazyBreakIterator.secondToLastCharacter()); - CharacterType lastCh = - pos > 0 ? str[pos - 1] - : static_cast<CharacterType>(lazyBreakIterator.lastCharacter()); + UChar lastLastCh = + pos > 1 ? str[pos - 2] : lazyBreakIterator.secondToLastCharacter(); + UChar lastCh = pos > 0 ? str[pos - 1] : lazyBreakIterator.lastCharacter(); ULineBreak lastLineBreak; if (lineBreakType == LineBreakType::BreakAll) lastLineBreak = lineBreakPropertyValue(lastLastCh, lastCh);
diff --git a/third_party/WebKit/Source/web/BUILD.gn b/third_party/WebKit/Source/web/BUILD.gn index 3408ee1..18cc77e 100644 --- a/third_party/WebKit/Source/web/BUILD.gn +++ b/third_party/WebKit/Source/web/BUILD.gn
@@ -142,7 +142,6 @@ "WebAssociatedURLLoaderImpl.h", "WebBlob.cpp", "WebCSSParser.cpp", - "WebCache.cpp", "WebColorSuggestion.cpp", "WebCryptoNormalize.cpp", "WebCustomElement.cpp",
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.cpp b/third_party/WebKit/Source/web/ChromeClientImpl.cpp index 617bc5e..3f3e86d 100644 --- a/third_party/WebKit/Source/web/ChromeClientImpl.cpp +++ b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
@@ -1067,11 +1067,6 @@ webframe->autofillClient()->didAssociateFormControlsDynamically(); } -void ChromeClientImpl::didCancelCompositionOnSelectionChange() { - if (m_webView->client()) - m_webView->client()->didCancelCompositionOnSelectionChange(); -} - void ChromeClientImpl::resetInputMethod() { if (m_webView->client()) m_webView->client()->resetInputMethod();
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.h b/third_party/WebKit/Source/web/ChromeClientImpl.h index 4d94948b..2501161 100644 --- a/third_party/WebKit/Source/web/ChromeClientImpl.h +++ b/third_party/WebKit/Source/web/ChromeClientImpl.h
@@ -204,7 +204,6 @@ void textFieldDataListChanged(HTMLInputElement&) override; void ajaxSucceeded(LocalFrame*) override; - void didCancelCompositionOnSelectionChange() override; void resetInputMethod() override; void showVirtualKeyboardOnElementFocus() override;
diff --git a/third_party/WebKit/Source/web/ExternalPopupMenuTest.cpp b/third_party/WebKit/Source/web/ExternalPopupMenuTest.cpp index 81bbf3b..5172b469 100644 --- a/third_party/WebKit/Source/web/ExternalPopupMenuTest.cpp +++ b/third_party/WebKit/Source/web/ExternalPopupMenuTest.cpp
@@ -17,8 +17,8 @@ #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebURLLoaderMockFactory.h" -#include "public/web/WebCache.h" #include "public/web/WebExternalPopupMenu.h" #include "public/web/WebPopupMenuInfo.h" #include "public/web/WebSettings.h"
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp index 2ece4781..3ccc62e 100644 --- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp +++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
@@ -405,9 +405,12 @@ m_webFrame->client()->willCommitProvisionalLoad(m_webFrame); } -void FrameLoaderClientImpl::dispatchDidStartProvisionalLoad() { - if (m_webFrame->client()) - m_webFrame->client()->didStartProvisionalLoad(m_webFrame); +void FrameLoaderClientImpl::dispatchDidStartProvisionalLoad( + DocumentLoader* loader) { + if (m_webFrame->client()) { + m_webFrame->client()->didStartProvisionalLoad( + WebDataSourceImpl::fromDocumentLoader(loader)); + } if (WebDevToolsAgentImpl* devTools = devToolsAgent()) devTools->didStartProvisionalLoad(m_webFrame->frame()); }
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h index 4374262..bede8e1 100644 --- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h +++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
@@ -92,7 +92,7 @@ HistoryCommitType, bool contentInitiated) override; void dispatchWillCommitProvisionalLoad() override; - void dispatchDidStartProvisionalLoad() override; + void dispatchDidStartProvisionalLoad(DocumentLoader*) override; void dispatchDidReceiveTitle(const String&) override; void dispatchDidChangeIcons(IconType) override; void dispatchDidCommitLoad(HistoryItem*, HistoryCommitType) override;
diff --git a/third_party/WebKit/Source/web/LinkHighlightImplTest.cpp b/third_party/WebKit/Source/web/LinkHighlightImplTest.cpp index 512dca62..28c879f 100644 --- a/third_party/WebKit/Source/web/LinkHighlightImplTest.cpp +++ b/third_party/WebKit/Source/web/LinkHighlightImplTest.cpp
@@ -36,12 +36,12 @@ #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebContentLayer.h" #include "public/platform/WebFloatPoint.h" #include "public/platform/WebInputEvent.h" #include "public/platform/WebSize.h" #include "public/platform/WebURLLoaderMockFactory.h" -#include "public/web/WebCache.h" #include "public/web/WebFrame.h" #include "public/web/WebFrameClient.h" #include "public/web/WebViewClient.h"
diff --git a/third_party/WebKit/Source/web/WebAssociatedURLLoaderImplTest.cpp b/third_party/WebKit/Source/web/WebAssociatedURLLoaderImplTest.cpp index ac08fca..73ae1b8 100644 --- a/third_party/WebKit/Source/web/WebAssociatedURLLoaderImplTest.cpp +++ b/third_party/WebKit/Source/web/WebAssociatedURLLoaderImplTest.cpp
@@ -30,9 +30,11 @@ #include "public/web/WebAssociatedURLLoader.h" +#include <memory> #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebString.h" #include "public/platform/WebThread.h" #include "public/platform/WebURL.h" @@ -41,7 +43,6 @@ #include "public/platform/WebURLResponse.h" #include "public/web/WebAssociatedURLLoaderClient.h" #include "public/web/WebAssociatedURLLoaderOptions.h" -#include "public/web/WebCache.h" #include "public/web/WebFrame.h" #include "public/web/WebView.h" #include "testing/gtest/include/gtest/gtest.h" @@ -49,7 +50,6 @@ #include "wtf/PtrUtil.h" #include "wtf/text/CString.h" #include "wtf/text/WTFString.h" -#include <memory> using blink::URLTestHelpers::toKURL; using blink::testing::runPendingTasks;
diff --git a/third_party/WebKit/Source/web/WebEmbeddedWorkerImplTest.cpp b/third_party/WebKit/Source/web/WebEmbeddedWorkerImplTest.cpp index 2a7778f..bb6888a 100644 --- a/third_party/WebKit/Source/web/WebEmbeddedWorkerImplTest.cpp +++ b/third_party/WebKit/Source/web/WebEmbeddedWorkerImplTest.cpp
@@ -4,20 +4,20 @@ #include "public/web/WebEmbeddedWorker.h" +#include <memory> #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebURLLoaderMockFactory.h" #include "public/platform/WebURLResponse.h" #include "public/platform/modules/serviceworker/WebServiceWorkerProvider.h" -#include "public/web/WebCache.h" #include "public/web/WebEmbeddedWorkerStartData.h" #include "public/web/WebSettings.h" #include "public/web/modules/serviceworker/WebServiceWorkerContextClient.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "wtf/PtrUtil.h" -#include <memory> namespace blink { namespace {
diff --git a/third_party/WebKit/Source/web/WebFrameWidgetBase.cpp b/third_party/WebKit/Source/web/WebFrameWidgetBase.cpp index 5a34a0e..79e51fc7 100644 --- a/third_party/WebKit/Source/web/WebFrameWidgetBase.cpp +++ b/third_party/WebKit/Source/web/WebFrameWidgetBase.cpp
@@ -72,14 +72,17 @@ modifiers); } -void WebFrameWidgetBase::dragTargetDragLeave() { +void WebFrameWidgetBase::dragTargetDragLeave(const WebPoint& pointInViewport, + const WebPoint& screenPoint) { DCHECK(m_currentDragData); if (ignoreInputEvents()) { cancelDrag(); return; } - DragData dragData(m_currentDragData.get(), IntPoint(), IntPoint(), + + WebPoint pointInRootFrame(viewportToRootFrame(pointInViewport)); + DragData dragData(m_currentDragData.get(), pointInRootFrame, screenPoint, static_cast<DragOperation>(m_operationsAllowed)); page()->dragController().dragExited(&dragData, *toCoreFrame(localRoot())); @@ -109,7 +112,7 @@ if (m_dragOperation == WebDragOperationNone) { // IPC RACE CONDITION: do not allow this drop. - dragTargetDragLeave(); + dragTargetDragLeave(pointInViewport, screenPoint); return; }
diff --git a/third_party/WebKit/Source/web/WebFrameWidgetBase.h b/third_party/WebKit/Source/web/WebFrameWidgetBase.h index 4d0e84d7..934df2a 100644 --- a/third_party/WebKit/Source/web/WebFrameWidgetBase.h +++ b/third_party/WebKit/Source/web/WebFrameWidgetBase.h
@@ -51,7 +51,8 @@ const WebPoint& screenPoint, WebDragOperationsMask operationsAllowed, int modifiers) override; - void dragTargetDragLeave() override; + void dragTargetDragLeave(const WebPoint& pointInViewport, + const WebPoint& screenPoint) override; void dragTargetDrop(const WebDragData&, const WebPoint& pointInViewport, const WebPoint& screenPoint,
diff --git a/third_party/WebKit/Source/web/WebKit.cpp b/third_party/WebKit/Source/web/WebKit.cpp index 86b3d94..ccc79f2 100644 --- a/third_party/WebKit/Source/web/WebKit.cpp +++ b/third_party/WebKit/Source/web/WebKit.cpp
@@ -91,23 +91,6 @@ } } -void shutdown() { - ThreadState::current()->cleanupMainThread(); - - // currentThread() is null if we are running on a thread without a message - // loop. - if (WebThread* currentThread = Platform::current()->currentThread()) { - currentThread->removeTaskObserver(s_endOfTaskRunner); - s_endOfTaskRunner = nullptr; - } - - modulesInitializer().shutdown(); - - V8Initializer::shutdownMainThread(); - - Platform::shutdown(); -} - v8::Isolate* mainThreadIsolate() { return V8PerIsolateData::mainThreadIsolate(); }
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp index f20abcf5..859ed996 100644 --- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp +++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -87,6 +87,9 @@ #include "web/WebLocalFrameImpl.h" +#include <algorithm> +#include <memory> +#include <utility> #include "bindings/core/v8/BindingSecurity.h" #include "bindings/core/v8/DOMWrapperWorld.h" #include "bindings/core/v8/ExceptionState.h" @@ -120,6 +123,7 @@ #include "core/frame/PageScaleConstraintsSet.h" #include "core/frame/RemoteFrame.h" #include "core/frame/Settings.h" +#include "core/frame/SmartClip.h" #include "core/frame/UseCounter.h" #include "core/frame/VisualViewport.h" #include "core/html/HTMLAnchorElement.h" @@ -229,9 +233,6 @@ #include "wtf/CurrentTime.h" #include "wtf/HashMap.h" #include "wtf/PtrUtil.h" -#include <algorithm> -#include <memory> -#include <utility> namespace blink { @@ -2383,4 +2384,36 @@ return m_inputMethodController.get(); } +void WebLocalFrameImpl::extractSmartClipData(WebRect rectInViewport, + WebString& clipText, + WebString& clipHtml) { + SmartClipData clipData = SmartClip(frame()).dataForRect(rectInViewport); + clipText = clipData.clipData(); + + WebPoint startPoint(rectInViewport.x, rectInViewport.y); + WebPoint endPoint(rectInViewport.x + rectInViewport.width, + rectInViewport.y + rectInViewport.height); + VisiblePosition startVisiblePosition = + visiblePositionForViewportPoint(startPoint); + VisiblePosition endVisiblePosition = + visiblePositionForViewportPoint(endPoint); + + Position startPosition = startVisiblePosition.deepEquivalent(); + Position endPosition = endVisiblePosition.deepEquivalent(); + + // document() will return null if -webkit-user-select is set to none. + if (!startPosition.document() || !endPosition.document()) + return; + + if (startPosition.compareTo(endPosition) <= 0) { + clipHtml = + createMarkup(startPosition, endPosition, AnnotateForInterchange, + ConvertBlocksToInlines::NotConvert, ResolveNonLocalURLs); + } else { + clipHtml = + createMarkup(endPosition, startPosition, AnnotateForInterchange, + ConvertBlocksToInlines::NotConvert, ResolveNonLocalURLs); + } +} + } // namespace blink
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.h b/third_party/WebKit/Source/web/WebLocalFrameImpl.h index 288cee89..5c8a850 100644 --- a/third_party/WebKit/Source/web/WebLocalFrameImpl.h +++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.h
@@ -298,6 +298,10 @@ base::SingleThreadTaskRunner* unthrottledTaskRunner() override; WebInputMethodControllerImpl* inputMethodController() const override; + void extractSmartClipData(WebRect rectInViewport, + WebString& clipText, + WebString& clipHtml) override; + // WebFrameImplBase methods: void initializeCoreFrame(FrameHost*, FrameOwner*,
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp index f7be30b..25d572c 100644 --- a/third_party/WebKit/Source/web/WebViewImpl.cpp +++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -57,7 +57,6 @@ #include "core/frame/PageScaleConstraintsSet.h" #include "core/frame/RemoteFrame.h" #include "core/frame/Settings.h" -#include "core/frame/SmartClip.h" #include "core/frame/UseCounter.h" #include "core/frame/VisualViewport.h" #include "core/html/HTMLMediaElement.h" @@ -3500,46 +3499,6 @@ frame->selection().setCaretBlinkingSuspended(false); } -void WebViewImpl::extractSmartClipData(WebRect rectInViewport, - WebString& clipText, - WebString& clipHtml, - WebRect& clipRectInViewport) { - LocalFrame* localFrame = toLocalFrame(focusedCoreFrame()); - if (!localFrame) - return; - SmartClipData clipData = SmartClip(localFrame).dataForRect(rectInViewport); - clipText = clipData.clipData(); - clipRectInViewport = clipData.rectInViewport(); - - WebLocalFrameImpl* frame = mainFrameImpl(); - if (!frame) - return; - WebPoint startPoint(rectInViewport.x, rectInViewport.y); - WebPoint endPoint(rectInViewport.x + rectInViewport.width, - rectInViewport.y + rectInViewport.height); - VisiblePosition startVisiblePosition = - frame->visiblePositionForViewportPoint(startPoint); - VisiblePosition endVisiblePosition = - frame->visiblePositionForViewportPoint(endPoint); - - Position startPosition = startVisiblePosition.deepEquivalent(); - Position endPosition = endVisiblePosition.deepEquivalent(); - - // document() will return null if -webkit-user-select is set to none. - if (!startPosition.document() || !endPosition.document()) - return; - - if (startPosition.compareTo(endPosition) <= 0) { - clipHtml = - createMarkup(startPosition, endPosition, AnnotateForInterchange, - ConvertBlocksToInlines::NotConvert, ResolveNonLocalURLs); - } else { - clipHtml = - createMarkup(endPosition, startPosition, AnnotateForInterchange, - ConvertBlocksToInlines::NotConvert, ResolveNonLocalURLs); - } -} - void WebViewImpl::hidePopups() { cancelPagePopup(); }
diff --git a/third_party/WebKit/Source/web/WebViewImpl.h b/third_party/WebKit/Source/web/WebViewImpl.h index 6aef001..8870df1 100644 --- a/third_party/WebKit/Source/web/WebViewImpl.h +++ b/third_party/WebKit/Source/web/WebViewImpl.h
@@ -250,7 +250,6 @@ void performCustomContextMenuAction(unsigned action) override; void showContextMenu() override; void didCloseContextMenu() override; - void extractSmartClipData(WebRect, WebString&, WebString&, WebRect&) override; void hidePopups() override; void setPageOverlayColor(WebColor) override; WebPageImportanceSignals* pageImportanceSignals() override;
diff --git a/third_party/WebKit/Source/web/mac/WebSubstringUtil.mm b/third_party/WebKit/Source/web/mac/WebSubstringUtil.mm index 025b7e5..34ef2bc 100644 --- a/third_party/WebKit/Source/web/mac/WebSubstringUtil.mm +++ b/third_party/WebKit/Source/web/mac/WebSubstringUtil.mm
@@ -41,8 +41,10 @@ #include "core/editing/FrameSelection.h" #include "core/editing/PlainTextRange.h" #include "core/editing/iterators/TextIterator.h" +#include "core/frame/FrameHost.h" #include "core/frame/FrameView.h" #include "core/frame/LocalFrame.h" +#include "core/frame/VisualViewport.h" #include "core/html/HTMLElement.h" #include "core/layout/HitTestResult.h" #include "core/layout/LayoutObject.h" @@ -60,7 +62,8 @@ using namespace blink; static NSAttributedString* attributedSubstringFromRange( - const EphemeralRange& range) { + const EphemeralRange& range, + float fontScale) { NSMutableAttributedString* string = [[NSMutableAttributedString alloc] init]; NSMutableDictionary* attrs = [NSMutableDictionary dictionary]; size_t length = range.endPosition().computeOffsetInContainerNode() - @@ -87,8 +90,9 @@ continue; const ComputedStyle* style = layoutObject->style(); - const FontPlatformData& fontPlatformData = + FontPlatformData fontPlatformData = style->font().primaryFont()->platformData(); + fontPlatformData.m_textSize *= fontScale; NSFont* font = toNSFont(fontPlatformData.ctFont()); // If the platform font can't be loaded, or the size is incorrect comparing // to the computed style, it's likely that the site is using a web font. @@ -96,12 +100,14 @@ // TODO(rsesek): Change the font activation flags to allow other processes // to use the font. // TODO(shuchen): Support scaling the font as necessary according to CSS - // transforms. + // transforms, not just pinch-zoom. if (!font || floor(fontPlatformData.size()) != - floor([[font fontDescriptor] pointSize])) + floor([[font fontDescriptor] pointSize])) { font = [NSFont - systemFontOfSize:style->font().getFontDescription().computedSize()]; + systemFontOfSize:style->font().getFontDescription().computedSize() * + fontScale]; + } [attrs setObject:font forKey:NSFontAttributeName]; if (style->visitedDependentColor(CSSPropertyColor).alpha()) @@ -132,19 +138,16 @@ WebPoint getBaselinePoint(FrameView* frameView, const EphemeralRange& range, NSAttributedString* string) { - // Compute bottom left corner and convert to AppKit coordinates. // TODO(yosin): We shold avoid to create |Range| object. See crbug.com/529985. - // TODO(shuchen): Support page-zoom for getting the baseline point. IntRect stringRect = - frameView->contentsToRootFrame(createRange(range)->boundingBox()); + frameView->contentsToViewport(createRange(range)->boundingBox()); IntPoint stringPoint = stringRect.minXMaxYCorner(); - stringPoint.setY(frameView->root()->height() - stringPoint.y()); // Adjust for the font's descender. AppKit wants the baseline point. if ([string length]) { NSDictionary* attributes = [string attributesAtIndex:0 effectiveRange:NULL]; if (NSFont* font = [attributes objectForKey:NSFontAttributeName]) - stringPoint.move(0, ceil(-[font descender])); + stringPoint.move(0, ceil([font descender])); } return stringPoint; } @@ -175,7 +178,8 @@ const EphemeralRange wordRange = selection.toNormalizedEphemeralRange(); // Convert to NSAttributedString. - NSAttributedString* string = attributedSubstringFromRange(wordRange); + NSAttributedString* string = attributedSubstringFromRange( + wordRange, frame->host()->visualViewport().scale()); baselinePoint = getBaselinePoint(frame->view(), wordRange, string); return string; } @@ -205,7 +209,8 @@ if (ephemeralRange.isNull()) return nil; - NSAttributedString* result = attributedSubstringFromRange(ephemeralRange); + NSAttributedString* result = attributedSubstringFromRange( + ephemeralRange, frame->host()->visualViewport().scale()); if (baselinePoint) *baselinePoint = getBaselinePoint(frame->view(), ephemeralRange, result); return result;
diff --git a/third_party/WebKit/Source/web/tests/ActivityLoggerTest.cpp b/third_party/WebKit/Source/web/tests/ActivityLoggerTest.cpp index 783b060..32939ff6 100644 --- a/third_party/WebKit/Source/web/tests/ActivityLoggerTest.cpp +++ b/third_party/WebKit/Source/web/tests/ActivityLoggerTest.cpp
@@ -2,18 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <v8.h> #include "bindings/core/v8/ScriptController.h" #include "bindings/core/v8/ScriptSourceCode.h" #include "bindings/core/v8/V8Binding.h" #include "bindings/core/v8/V8DOMActivityLogger.h" -#include "public/web/WebCache.h" +#include "public/platform/WebCache.h" #include "testing/gtest/include/gtest/gtest.h" #include "web/WebLocalFrameImpl.h" #include "web/tests/FrameTestHelpers.h" #include "wtf/Forward.h" #include "wtf/PtrUtil.h" #include "wtf/text/Base64.h" -#include <v8.h> namespace blink {
diff --git a/third_party/WebKit/Source/web/tests/BrowserControlsTest.cpp b/third_party/WebKit/Source/web/tests/BrowserControlsTest.cpp index 08243a0..cb5b2b2 100644 --- a/third_party/WebKit/Source/web/tests/BrowserControlsTest.cpp +++ b/third_party/WebKit/Source/web/tests/BrowserControlsTest.cpp
@@ -38,8 +38,8 @@ #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebURLLoaderMockFactory.h" -#include "public/web/WebCache.h" #include "public/web/WebElement.h" #include "public/web/WebSettings.h" #include "testing/gmock/include/gmock/gmock.h"
diff --git a/third_party/WebKit/Source/web/tests/CompositorWorkerTest.cpp b/third_party/WebKit/Source/web/tests/CompositorWorkerTest.cpp index 26523e6..c03b411 100644 --- a/third_party/WebKit/Source/web/tests/CompositorWorkerTest.cpp +++ b/third_party/WebKit/Source/web/tests/CompositorWorkerTest.cpp
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <gtest/gtest.h> #include <memory> #include "core/frame/FrameView.h" #include "core/layout/api/LayoutViewItem.h" @@ -15,10 +16,10 @@ #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebLayer.h" #include "public/platform/WebLayerTreeView.h" #include "public/platform/WebURLLoaderMockFactory.h" -#include "public/web/WebCache.h" #include "public/web/WebSettings.h" #include "public/web/WebViewClient.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/third_party/WebKit/Source/web/tests/DocumentLoaderTest.cpp b/third_party/WebKit/Source/web/tests/DocumentLoaderTest.cpp index 7006a75..018bf6e88 100644 --- a/third_party/WebKit/Source/web/tests/DocumentLoaderTest.cpp +++ b/third_party/WebKit/Source/web/tests/DocumentLoaderTest.cpp
@@ -9,9 +9,9 @@ #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebURLLoaderClient.h" #include "public/platform/WebURLLoaderMockFactory.h" -#include "public/web/WebCache.h" #include "testing/gtest/include/gtest/gtest.h" #include "web/WebLocalFrameImpl.h" #include "web/tests/FrameTestHelpers.h"
diff --git a/third_party/WebKit/Source/web/tests/FrameSerializerTest.cpp b/third_party/WebKit/Source/web/tests/FrameSerializerTest.cpp index 0c37dafb..5865c77 100644 --- a/third_party/WebKit/Source/web/tests/FrameSerializerTest.cpp +++ b/third_party/WebKit/Source/web/tests/FrameSerializerTest.cpp
@@ -37,13 +37,13 @@ #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebString.h" #include "public/platform/WebThread.h" #include "public/platform/WebURL.h" #include "public/platform/WebURLLoaderMockFactory.h" #include "public/platform/WebURLRequest.h" #include "public/platform/WebURLResponse.h" -#include "public/web/WebCache.h" #include "public/web/WebSettings.h" #include "testing/gtest/include/gtest/gtest.h" #include "web/WebLocalFrameImpl.h"
diff --git a/third_party/WebKit/Source/web/tests/ImeOnFocusTest.cpp b/third_party/WebKit/Source/web/tests/ImeOnFocusTest.cpp index e906209..f86229d 100644 --- a/third_party/WebKit/Source/web/tests/ImeOnFocusTest.cpp +++ b/third_party/WebKit/Source/web/tests/ImeOnFocusTest.cpp
@@ -9,8 +9,8 @@ #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebURLLoaderMockFactory.h" -#include "public/web/WebCache.h" #include "public/web/WebDocument.h" #include "testing/gtest/include/gtest/gtest.h" #include "web/WebLocalFrameImpl.h"
diff --git a/third_party/WebKit/Source/web/tests/IntersectionObserverTest.cpp b/third_party/WebKit/Source/web/tests/IntersectionObserverTest.cpp index fd14a1e..2269127 100644 --- a/third_party/WebKit/Source/web/tests/IntersectionObserverTest.cpp +++ b/third_party/WebKit/Source/web/tests/IntersectionObserverTest.cpp
@@ -127,4 +127,39 @@ EXPECT_EQ(observerCallback->callCount(), 3); } +TEST_F(IntersectionObserverTest, DisconnectClearsNotifications) { + webView().resize(WebSize(800, 600)); + SimRequest mainResource("https://example.com/", "text/html"); + loadURL("https://example.com/"); + mainResource.complete( + "<div id='leading-space' style='height: 700px;'></div>" + "<div id='target'></div>" + "<div id='trailing-space' style='height: 700px;'></div>"); + + IntersectionObserverInit observerInit; + DummyExceptionStateForTesting exceptionState; + TestIntersectionObserverCallback* observerCallback = + new TestIntersectionObserverCallback(document()); + IntersectionObserver* observer = IntersectionObserver::create( + observerInit, *observerCallback, exceptionState); + ASSERT_FALSE(exceptionState.hadException()); + + Element* target = document().getElementById("target"); + ASSERT_TRUE(target); + observer->observe(target, exceptionState); + + compositor().beginFrame(); + testing::runPendingTasks(); + EXPECT_EQ(observerCallback->callCount(), 1); + + // If disconnect() is called while an observer has unsent notifications, + // those notifications should be discarded. + document().view()->layoutViewportScrollableArea()->setScrollOffset( + ScrollOffset(0, 300), ProgrammaticScroll); + compositor().beginFrame(); + observer->disconnect(); + testing::runPendingTasks(); + EXPECT_EQ(observerCallback->callCount(), 1); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/web/tests/LayoutGeometryMapTest.cpp b/third_party/WebKit/Source/web/tests/LayoutGeometryMapTest.cpp index 9039c25..f29212c 100644 --- a/third_party/WebKit/Source/web/tests/LayoutGeometryMapTest.cpp +++ b/third_party/WebKit/Source/web/tests/LayoutGeometryMapTest.cpp
@@ -38,8 +38,8 @@ #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebURLLoaderMockFactory.h" -#include "public/web/WebCache.h" #include "public/web/WebFrameClient.h" #include "testing/gtest/include/gtest/gtest.h" #include "web/WebLocalFrameImpl.h"
diff --git a/third_party/WebKit/Source/web/tests/ListenerLeakTest.cpp b/third_party/WebKit/Source/web/tests/ListenerLeakTest.cpp index a5db2b6..6be40e6 100644 --- a/third_party/WebKit/Source/web/tests/ListenerLeakTest.cpp +++ b/third_party/WebKit/Source/web/tests/ListenerLeakTest.cpp
@@ -33,8 +33,8 @@ #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebURLLoaderMockFactory.h" -#include "public/web/WebCache.h" #include "public/web/WebView.h" #include "testing/gtest/include/gtest/gtest.h" #include "web/tests/FrameTestHelpers.h"
diff --git a/third_party/WebKit/Source/web/tests/MHTMLTest.cpp b/third_party/WebKit/Source/web/tests/MHTMLTest.cpp index 7959a4b..ff98f0e 100644 --- a/third_party/WebKit/Source/web/tests/MHTMLTest.cpp +++ b/third_party/WebKit/Source/web/tests/MHTMLTest.cpp
@@ -40,12 +40,12 @@ #include "platform/weborigin/KURL.h" #include "platform/weborigin/SchemeRegistry.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebString.h" #include "public/platform/WebURL.h" #include "public/platform/WebURLLoaderMockFactory.h" #include "public/platform/WebURLRequest.h" #include "public/platform/WebURLResponse.h" -#include "public/web/WebCache.h" #include "public/web/WebDocument.h" #include "public/web/WebFrame.h" #include "public/web/WebView.h"
diff --git a/third_party/WebKit/Source/web/tests/PrerenderingTest.cpp b/third_party/WebKit/Source/web/tests/PrerenderingTest.cpp index 157ef611..0e3e67b4 100644 --- a/third_party/WebKit/Source/web/tests/PrerenderingTest.cpp +++ b/third_party/WebKit/Source/web/tests/PrerenderingTest.cpp
@@ -35,11 +35,11 @@ #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebPrerender.h" #include "public/platform/WebPrerenderingSupport.h" #include "public/platform/WebString.h" #include "public/platform/WebURLLoaderMockFactory.h" -#include "public/web/WebCache.h" #include "public/web/WebFrame.h" #include "public/web/WebPrerendererClient.h" #include "public/web/WebScriptSource.h"
diff --git a/third_party/WebKit/Source/web/tests/ProgrammaticScrollTest.cpp b/third_party/WebKit/Source/web/tests/ProgrammaticScrollTest.cpp index 67c2508..015bdad 100644 --- a/third_party/WebKit/Source/web/tests/ProgrammaticScrollTest.cpp +++ b/third_party/WebKit/Source/web/tests/ProgrammaticScrollTest.cpp
@@ -4,9 +4,9 @@ #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebInputEvent.h" #include "public/platform/WebURLLoaderMockFactory.h" -#include "public/web/WebCache.h" #include "public/web/WebFrame.h" #include "public/web/WebFrameClient.h" #include "public/web/WebHistoryItem.h"
diff --git a/third_party/WebKit/Source/web/tests/RootScrollerTest.cpp b/third_party/WebKit/Source/web/tests/RootScrollerTest.cpp index a969a391..e6a2308 100644 --- a/third_party/WebKit/Source/web/tests/RootScrollerTest.cpp +++ b/third_party/WebKit/Source/web/tests/RootScrollerTest.cpp
@@ -21,8 +21,8 @@ #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebURLLoaderMockFactory.h" -#include "public/web/WebCache.h" #include "public/web/WebConsoleMessage.h" #include "public/web/WebRemoteFrame.h" #include "public/web/WebScriptSource.h"
diff --git a/third_party/WebKit/Source/web/tests/ScreenWakeLockTest.cpp b/third_party/WebKit/Source/web/tests/ScreenWakeLockTest.cpp index 4a4ac281..33f46db 100644 --- a/third_party/WebKit/Source/web/tests/ScreenWakeLockTest.cpp +++ b/third_party/WebKit/Source/web/tests/ScreenWakeLockTest.cpp
@@ -13,9 +13,9 @@ #include "platform/testing/UnitTestHelpers.h" #include "public/platform/InterfaceProvider.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebPageVisibilityState.h" #include "public/platform/WebURLLoaderMockFactory.h" -#include "public/web/WebCache.h" #include "testing/gtest/include/gtest/gtest.h" #include "web/WebLocalFrameImpl.h" #include "web/tests/FrameTestHelpers.h"
diff --git a/third_party/WebKit/Source/web/tests/ScrollingCoordinatorTest.cpp b/third_party/WebKit/Source/web/tests/ScrollingCoordinatorTest.cpp index c7be239..e4a01a9 100644 --- a/third_party/WebKit/Source/web/tests/ScrollingCoordinatorTest.cpp +++ b/third_party/WebKit/Source/web/tests/ScrollingCoordinatorTest.cpp
@@ -38,14 +38,15 @@ #include "platform/geometry/IntPoint.h" #include "platform/geometry/IntRect.h" #include "platform/graphics/GraphicsLayer.h" +#include "platform/testing/RuntimeEnabledFeaturesTestHelpers.h" #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebLayer.h" #include "public/platform/WebLayerPositionConstraint.h" #include "public/platform/WebLayerTreeView.h" #include "public/platform/WebURLLoaderMockFactory.h" -#include "public/web/WebCache.h" #include "public/web/WebSettings.h" #include "public/web/WebViewClient.h" #include "testing/gtest/include/gtest/gtest.h" @@ -55,9 +56,13 @@ namespace blink { -class ScrollingCoordinatorTest : public ::testing::Test { +class ScrollingCoordinatorTest : public ::testing::Test, + public ::testing::WithParamInterface<bool>, + private ScopedRootLayerScrollingForTest { public: - ScrollingCoordinatorTest() : m_baseURL("http://www.test.com/") { + ScrollingCoordinatorTest() + : ScopedRootLayerScrollingForTest(GetParam()), + m_baseURL("http://www.test.com/") { m_helper.initialize(true, nullptr, &m_mockWebViewClient, nullptr, &configureSettings); webViewImpl()->resize(IntSize(320, 240)); @@ -85,6 +90,11 @@ FrameTestHelpers::loadFrame(webViewImpl()->mainFrame(), url); } + void loadHTML(const std::string& html) { + FrameTestHelpers::loadHTMLString(webViewImpl()->mainFrame(), html, + URLTestHelpers::toKURL("about:blank")); + } + void forceFullCompositingUpdate() { webViewImpl()->updateAllLifecyclePhases(); } @@ -96,13 +106,9 @@ } WebLayer* getRootScrollLayer() { - PaintLayerCompositor* compositor = - frame()->contentLayoutItem().compositor(); - DCHECK(compositor); - DCHECK(compositor->scrollLayer()); - - WebLayer* webScrollLayer = compositor->scrollLayer()->platformLayer(); - return webScrollLayer; + GraphicsLayer* layer = + frame()->view()->layoutViewportScrollableArea()->layerForScrolling(); + return layer ? layer->platformLayer() : nullptr; } WebViewImpl* webViewImpl() const { return m_helper.webView(); } @@ -114,9 +120,6 @@ return webViewImpl()->layerTreeView(); } - void styleRelatedMainThreadScrollingReasonTest(const std::string&, - const uint32_t); - protected: std::string m_baseURL; FrameTestHelpers::TestWebViewClient m_mockWebViewClient; @@ -131,8 +134,11 @@ FrameTestHelpers::WebViewHelper m_helper; }; -TEST_F(ScrollingCoordinatorTest, fastScrollingByDefault) { - navigateTo("about:blank"); +INSTANTIATE_TEST_CASE_P(All, ScrollingCoordinatorTest, ::testing::Bool()); + +TEST_P(ScrollingCoordinatorTest, fastScrollingByDefault) { + webViewImpl()->resize(WebSize(800, 600)); + loadHTML("<div id='spacer' style='height: 1000px'></div>"); forceFullCompositingUpdate(); // Make sure the scrolling coordinator is active. @@ -144,6 +150,7 @@ // Fast scrolling should be enabled by default. WebLayer* rootScrollLayer = getRootScrollLayer(); + ASSERT_TRUE(rootScrollLayer); ASSERT_TRUE(rootScrollLayer->scrollable()); ASSERT_FALSE(rootScrollLayer->shouldScrollOnMainThread()); ASSERT_EQ(WebEventListenerProperties::Nothing, @@ -159,8 +166,9 @@ ASSERT_FALSE(innerViewportScrollLayer->shouldScrollOnMainThread()); } -TEST_F(ScrollingCoordinatorTest, fastScrollingCanBeDisabledWithSetting) { - navigateTo("about:blank"); +TEST_P(ScrollingCoordinatorTest, fastScrollingCanBeDisabledWithSetting) { + webViewImpl()->resize(WebSize(800, 600)); + loadHTML("<div id='spacer' style='height: 1000px'></div>"); webViewImpl()->settings()->setThreadedScrollingEnabled(false); forceFullCompositingUpdate(); @@ -173,6 +181,7 @@ // Main scrolling should be enabled with the setting override. WebLayer* rootScrollLayer = getRootScrollLayer(); + ASSERT_TRUE(rootScrollLayer); ASSERT_TRUE(rootScrollLayer->scrollable()); ASSERT_TRUE(rootScrollLayer->shouldScrollOnMainThread()); @@ -183,7 +192,7 @@ ASSERT_TRUE(innerViewportScrollLayer->shouldScrollOnMainThread()); } -TEST_F(ScrollingCoordinatorTest, fastFractionalScrollingDiv) { +TEST_P(ScrollingCoordinatorTest, fastFractionalScrollingDiv) { bool origFractionalOffsetsEnabled = RuntimeEnabledFeatures::fractionalScrollOffsetsEnabled(); RuntimeEnabledFeatures::setFractionalScrollOffsetsEnabled(true); @@ -243,13 +252,14 @@ return graphicsLayer->platformLayer(); } -TEST_F(ScrollingCoordinatorTest, fastScrollingForFixedPosition) { +TEST_P(ScrollingCoordinatorTest, fastScrollingForFixedPosition) { registerMockedHttpURLLoad("fixed-position.html"); navigateTo(m_baseURL + "fixed-position.html"); forceFullCompositingUpdate(); // Fixed position should not fall back to main thread scrolling. WebLayer* rootScrollLayer = getRootScrollLayer(); + ASSERT_TRUE(rootScrollLayer); ASSERT_FALSE(rootScrollLayer->shouldScrollOnMainThread()); Document* document = frame()->document(); @@ -335,13 +345,14 @@ } } -TEST_F(ScrollingCoordinatorTest, fastScrollingForStickyPosition) { +TEST_P(ScrollingCoordinatorTest, fastScrollingForStickyPosition) { registerMockedHttpURLLoad("sticky-position.html"); navigateTo(m_baseURL + "sticky-position.html"); forceFullCompositingUpdate(); // Sticky position should not fall back to main thread scrolling. WebLayer* rootScrollLayer = getRootScrollLayer(); + ASSERT_TRUE(rootScrollLayer); EXPECT_FALSE(rootScrollLayer->shouldScrollOnMainThread()); Document* document = frame()->document(); @@ -441,7 +452,7 @@ } } -TEST_F(ScrollingCoordinatorTest, touchEventHandler) { +TEST_P(ScrollingCoordinatorTest, touchEventHandler) { registerMockedHttpURLLoad("touch-event-handler.html"); navigateTo(m_baseURL + "touch-event-handler.html"); forceFullCompositingUpdate(); @@ -451,7 +462,7 @@ WebEventListenerClass::TouchStartOrMove)); } -TEST_F(ScrollingCoordinatorTest, touchEventHandlerPassive) { +TEST_P(ScrollingCoordinatorTest, touchEventHandlerPassive) { registerMockedHttpURLLoad("touch-event-handler-passive.html"); navigateTo(m_baseURL + "touch-event-handler-passive.html"); forceFullCompositingUpdate(); @@ -461,7 +472,7 @@ WebEventListenerClass::TouchStartOrMove)); } -TEST_F(ScrollingCoordinatorTest, touchEventHandlerBoth) { +TEST_P(ScrollingCoordinatorTest, touchEventHandlerBoth) { registerMockedHttpURLLoad("touch-event-handler-both.html"); navigateTo(m_baseURL + "touch-event-handler-both.html"); forceFullCompositingUpdate(); @@ -471,7 +482,7 @@ WebEventListenerClass::TouchStartOrMove)); } -TEST_F(ScrollingCoordinatorTest, wheelEventHandler) { +TEST_P(ScrollingCoordinatorTest, wheelEventHandler) { registerMockedHttpURLLoad("wheel-event-handler.html"); navigateTo(m_baseURL + "wheel-event-handler.html"); forceFullCompositingUpdate(); @@ -481,7 +492,7 @@ WebEventListenerClass::MouseWheel)); } -TEST_F(ScrollingCoordinatorTest, wheelEventHandlerPassive) { +TEST_P(ScrollingCoordinatorTest, wheelEventHandlerPassive) { registerMockedHttpURLLoad("wheel-event-handler-passive.html"); navigateTo(m_baseURL + "wheel-event-handler-passive.html"); forceFullCompositingUpdate(); @@ -491,7 +502,7 @@ WebEventListenerClass::MouseWheel)); } -TEST_F(ScrollingCoordinatorTest, wheelEventHandlerBoth) { +TEST_P(ScrollingCoordinatorTest, wheelEventHandlerBoth) { registerMockedHttpURLLoad("wheel-event-handler-both.html"); navigateTo(m_baseURL + "wheel-event-handler-both.html"); forceFullCompositingUpdate(); @@ -501,7 +512,7 @@ WebEventListenerClass::MouseWheel)); } -TEST_F(ScrollingCoordinatorTest, scrollEventHandler) { +TEST_P(ScrollingCoordinatorTest, scrollEventHandler) { registerMockedHttpURLLoad("scroll-event-handler.html"); navigateTo(m_baseURL + "scroll-event-handler.html"); forceFullCompositingUpdate(); @@ -509,7 +520,7 @@ ASSERT_TRUE(webLayerTreeView()->haveScrollEventHandlers()); } -TEST_F(ScrollingCoordinatorTest, updateEventHandlersDuringTeardown) { +TEST_P(ScrollingCoordinatorTest, updateEventHandlersDuringTeardown) { registerMockedHttpURLLoad("scroll-event-handler-window.html"); navigateTo(m_baseURL + "scroll-event-handler-window.html"); forceFullCompositingUpdate(); @@ -519,16 +530,17 @@ frame()->document()->shutdown(); } -TEST_F(ScrollingCoordinatorTest, clippedBodyTest) { +TEST_P(ScrollingCoordinatorTest, clippedBodyTest) { registerMockedHttpURLLoad("clipped-body.html"); navigateTo(m_baseURL + "clipped-body.html"); forceFullCompositingUpdate(); WebLayer* rootScrollLayer = getRootScrollLayer(); + ASSERT_TRUE(rootScrollLayer); ASSERT_EQ(0u, rootScrollLayer->nonFastScrollableRegion().size()); } -TEST_F(ScrollingCoordinatorTest, overflowScrolling) { +TEST_P(ScrollingCoordinatorTest, overflowScrolling) { registerMockedHttpURLLoad("overflow-scrolling.html"); navigateTo(m_baseURL + "overflow-scrolling.html"); forceFullCompositingUpdate(); @@ -574,7 +586,7 @@ #endif } -TEST_F(ScrollingCoordinatorTest, overflowHidden) { +TEST_P(ScrollingCoordinatorTest, overflowHidden) { registerMockedHttpURLLoad("overflow-hidden.html"); navigateTo(m_baseURL + "overflow-hidden.html"); forceFullCompositingUpdate(); @@ -635,7 +647,7 @@ ASSERT_TRUE(webScrollLayer->userScrollableVertical()); } -TEST_F(ScrollingCoordinatorTest, iframeScrolling) { +TEST_P(ScrollingCoordinatorTest, iframeScrolling) { registerMockedHttpURLLoad("iframe-scrolling.html"); registerMockedHttpURLLoad("iframe-scrolling-inner.html"); navigateTo(m_baseURL + "iframe-scrolling.html"); @@ -661,25 +673,32 @@ PaintLayerCompositor* innerCompositor = innerLayoutViewItem.compositor(); ASSERT_TRUE(innerCompositor->inCompositingMode()); - ASSERT_TRUE(innerCompositor->scrollLayer()); - GraphicsLayer* scrollLayer = innerCompositor->scrollLayer(); - ASSERT_EQ(innerFrameView, scrollLayer->getScrollableArea()); + GraphicsLayer* scrollLayer = + innerFrameView->layoutViewportScrollableArea()->layerForScrolling(); + ASSERT_TRUE(scrollLayer); + ASSERT_EQ(innerFrameView->layoutViewportScrollableArea(), + scrollLayer->getScrollableArea()); WebLayer* webScrollLayer = scrollLayer->platformLayer(); ASSERT_TRUE(webScrollLayer->scrollable()); #if OS(ANDROID) // Now verify we've attached impl-side scrollbars onto the scrollbar layers - ASSERT_TRUE(innerCompositor->layerForHorizontalScrollbar()); - ASSERT_TRUE( - innerCompositor->layerForHorizontalScrollbar()->hasContentsLayer()); - ASSERT_TRUE(innerCompositor->layerForVerticalScrollbar()); - ASSERT_TRUE(innerCompositor->layerForVerticalScrollbar()->hasContentsLayer()); + GraphicsLayer* horizontalScrollbarLayer = + innerFrameView->layoutViewportScrollableArea() + ->layerForHorizontalScrollbar(); + ASSERT_TRUE(horizontalScrollbarLayer); + ASSERT_TRUE(horizontalScrollbarLayer->hasContentsLayer()); + GraphicsLayer* verticalScrollbarLayer = + innerFrameView->layoutViewportScrollableArea() + ->layerForVerticalScrollbar(); + ASSERT_TRUE(verticalScrollbarLayer); + ASSERT_TRUE(verticalScrollbarLayer->hasContentsLayer()); #endif } -TEST_F(ScrollingCoordinatorTest, rtlIframe) { +TEST_P(ScrollingCoordinatorTest, rtlIframe) { registerMockedHttpURLLoad("rtl-iframe.html"); registerMockedHttpURLLoad("rtl-iframe-inner.html"); navigateTo(m_baseURL + "rtl-iframe.html"); @@ -705,21 +724,26 @@ PaintLayerCompositor* innerCompositor = innerLayoutViewItem.compositor(); ASSERT_TRUE(innerCompositor->inCompositingMode()); - ASSERT_TRUE(innerCompositor->scrollLayer()); - GraphicsLayer* scrollLayer = innerCompositor->scrollLayer(); - ASSERT_EQ(innerFrameView, scrollLayer->getScrollableArea()); + GraphicsLayer* scrollLayer = + innerFrameView->layoutViewportScrollableArea()->layerForScrolling(); + ASSERT_TRUE(scrollLayer); + ASSERT_EQ(innerFrameView->layoutViewportScrollableArea(), + scrollLayer->getScrollableArea()); WebLayer* webScrollLayer = scrollLayer->platformLayer(); ASSERT_TRUE(webScrollLayer->scrollable()); int expectedScrollPosition = - 958 + - (innerFrameView->verticalScrollbar()->isOverlayScrollbar() ? 0 : 15); + 958 + (innerFrameView->layoutViewportScrollableArea() + ->verticalScrollbar() + ->isOverlayScrollbar() + ? 0 + : 15); ASSERT_EQ(expectedScrollPosition, webScrollLayer->scrollPositionDouble().x); } -TEST_F(ScrollingCoordinatorTest, setupScrollbarLayerShouldNotCrash) { +TEST_P(ScrollingCoordinatorTest, setupScrollbarLayerShouldNotCrash) { registerMockedHttpURLLoad("setup_scrollbar_layer_crash.html"); navigateTo(m_baseURL + "setup_scrollbar_layer_crash.html"); forceFullCompositingUpdate(); @@ -727,7 +751,7 @@ // an empty document by javascript. } -TEST_F(ScrollingCoordinatorTest, +TEST_P(ScrollingCoordinatorTest, scrollbarsForceMainThreadOrHaveWebScrollbarLayer) { registerMockedHttpURLLoad("trivial-scroller.html"); navigateTo(m_baseURL + "trivial-scroller.html"); @@ -754,10 +778,10 @@ } #if OS(MACOSX) || OS(ANDROID) -TEST_F(ScrollingCoordinatorTest, +TEST_P(ScrollingCoordinatorTest, DISABLED_setupScrollbarLayerShouldSetScrollLayerOpaque) #else -TEST_F(ScrollingCoordinatorTest, setupScrollbarLayerShouldSetScrollLayerOpaque) +TEST_P(ScrollingCoordinatorTest, setupScrollbarLayerShouldSetScrollLayerOpaque) #endif { registerMockedHttpURLLoad("wide_document.html"); @@ -768,7 +792,7 @@ ASSERT_TRUE(frameView); GraphicsLayer* scrollbarGraphicsLayer = - frameView->layerForHorizontalScrollbar(); + frameView->layoutViewportScrollableArea()->layerForHorizontalScrollbar(); ASSERT_TRUE(scrollbarGraphicsLayer); WebLayer* platformLayer = scrollbarGraphicsLayer->platformLayer(); @@ -783,19 +807,16 @@ ASSERT_EQ(platformLayer->opaque(), contentsLayer->opaque()); } -TEST_F(ScrollingCoordinatorTest, +TEST_P(ScrollingCoordinatorTest, FixedPositionLosingBackingShouldTriggerMainThreadScroll) { webViewImpl()->settings()->setPreferCompositingToLCDTextEnabled(false); registerMockedHttpURLLoad("fixed-position-losing-backing.html"); navigateTo(m_baseURL + "fixed-position-losing-backing.html"); forceFullCompositingUpdate(); - WebLayer* scrollLayer = frame() - ->page() - ->deprecatedLocalMainFrame() - ->view() - ->layerForScrolling() - ->platformLayer(); + WebLayer* scrollLayer = getRootScrollLayer(); + ASSERT_TRUE(scrollLayer); + Document* document = frame()->document(); Element* fixedPos = document->getElementById("fixed"); @@ -813,7 +834,7 @@ EXPECT_TRUE(scrollLayer->shouldScrollOnMainThread()); } -TEST_F(ScrollingCoordinatorTest, CustomScrollbarShouldTriggerMainThreadScroll) { +TEST_P(ScrollingCoordinatorTest, CustomScrollbarShouldTriggerMainThreadScroll) { webViewImpl()->settings()->setPreferCompositingToLCDTextEnabled(true); webViewImpl()->setDeviceScaleFactor(2.f); registerMockedHttpURLLoad("custom_scrollbar.html"); @@ -854,7 +875,7 @@ MainThreadScrollingReason::kCustomScrollbarScrolling); } -TEST_F(ScrollingCoordinatorTest, +TEST_P(ScrollingCoordinatorTest, BackgroundAttachmentFixedShouldTriggerMainThreadScroll) { registerMockedHttpURLLoad("iframe-background-attachment-fixed.html"); registerMockedHttpURLLoad("iframe-background-attachment-fixed-inner.html"); @@ -880,10 +901,12 @@ PaintLayerCompositor* innerCompositor = innerLayoutViewItem.compositor(); ASSERT_TRUE(innerCompositor->inCompositingMode()); - ASSERT_TRUE(innerCompositor->scrollLayer()); - GraphicsLayer* scrollLayer = innerCompositor->scrollLayer(); - ASSERT_EQ(innerFrameView, scrollLayer->getScrollableArea()); + GraphicsLayer* scrollLayer = + innerFrameView->layoutViewportScrollableArea()->layerForScrolling(); + ASSERT_TRUE(scrollLayer); + ASSERT_EQ(innerFrameView->layoutViewportScrollableArea(), + scrollLayer->getScrollableArea()); WebLayer* webScrollLayer = scrollLayer->platformLayer(); ASSERT_TRUE(webScrollLayer->scrollable()); @@ -902,7 +925,9 @@ layoutObject = iframe->layoutObject(); ASSERT_TRUE(layoutObject); - scrollLayer = layoutObject->frameView()->layerForScrolling(); + scrollLayer = layoutObject->frameView() + ->layoutViewportScrollableArea() + ->layerForScrolling(); ASSERT_TRUE(scrollLayer); webScrollLayer = scrollLayer->platformLayer(); @@ -923,7 +948,9 @@ layoutObject = iframe->layoutObject(); ASSERT_TRUE(layoutObject); - scrollLayer = layoutObject->frameView()->layerForScrolling(); + scrollLayer = layoutObject->frameView() + ->layoutViewportScrollableArea() + ->layerForScrolling(); ASSERT_TRUE(scrollLayer); webScrollLayer = scrollLayer->platformLayer(); @@ -934,7 +961,7 @@ // Upon resizing the content size, the main thread scrolling reason // kHasNonLayerViewportConstrainedObject should be updated on all frames -TEST_F(ScrollingCoordinatorTest, +TEST_P(ScrollingCoordinatorTest, RecalculateMainThreadScrollingReasonsUponResize) { webViewImpl()->settings()->setPreferCompositingToLCDTextEnabled(false); registerMockedHttpURLLoad("has-non-layer-viewport-constrained-objects.html"); @@ -948,29 +975,23 @@ LayoutObject* layoutObject = element->layoutObject(); ASSERT_TRUE(layoutObject); - GraphicsLayer* scrollLayer = layoutObject->frameView()->layerForScrolling(); - ASSERT_TRUE(scrollLayer); + GraphicsLayer* scrollLayer = layoutObject->frameView() + ->layoutViewportScrollableArea() + ->layerForScrolling(); + WebLayer* webScrollLayer; - WebLayer* webScrollLayer = scrollLayer->platformLayer(); - ASSERT_TRUE(webScrollLayer->scrollable()); - ASSERT_FALSE( - webScrollLayer->mainThreadScrollingReasons() & - MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects); - - Element* iframe = frame()->document()->getElementById("iframe"); - ASSERT_TRUE(iframe); - - layoutObject = iframe->layoutObject(); - ASSERT_TRUE(layoutObject); - - scrollLayer = layoutObject->frameView()->layerForScrolling(); - ASSERT_TRUE(scrollLayer); - - webScrollLayer = scrollLayer->platformLayer(); - ASSERT_TRUE(webScrollLayer->scrollable()); - ASSERT_FALSE( - webScrollLayer->mainThreadScrollingReasons() & - MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects); + if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) { + // When RLS is enabled, the LayoutView won't have a scrolling contents + // because it does not overflow. + ASSERT_FALSE(scrollLayer); + } else { + ASSERT_TRUE(scrollLayer); + webScrollLayer = scrollLayer->platformLayer(); + ASSERT_TRUE(webScrollLayer->scrollable()); + ASSERT_FALSE( + webScrollLayer->mainThreadScrollingReasons() & + MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects); + } // When the div becomes to scrollable it should scroll on main thread element->setAttribute("style", @@ -981,19 +1002,9 @@ layoutObject = element->layoutObject(); ASSERT_TRUE(layoutObject); - scrollLayer = layoutObject->frameView()->layerForScrolling(); - ASSERT_TRUE(scrollLayer); - - webScrollLayer = scrollLayer->platformLayer(); - ASSERT_TRUE(webScrollLayer->scrollable()); - ASSERT_TRUE( - webScrollLayer->mainThreadScrollingReasons() & - MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects); - - layoutObject = iframe->layoutObject(); - ASSERT_TRUE(layoutObject); - - scrollLayer = layoutObject->frameView()->layerForScrolling(); + scrollLayer = layoutObject->frameView() + ->layoutViewportScrollableArea() + ->layerForScrolling(); ASSERT_TRUE(scrollLayer); webScrollLayer = scrollLayer->platformLayer(); @@ -1011,26 +1022,21 @@ layoutObject = element->layoutObject(); ASSERT_TRUE(layoutObject); - scrollLayer = layoutObject->frameView()->layerForScrolling(); - ASSERT_TRUE(scrollLayer); - - webScrollLayer = scrollLayer->platformLayer(); - ASSERT_TRUE(webScrollLayer->scrollable()); - ASSERT_FALSE( - webScrollLayer->mainThreadScrollingReasons() & - MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects); - - layoutObject = iframe->layoutObject(); - ASSERT_TRUE(layoutObject); - - scrollLayer = layoutObject->frameView()->layerForScrolling(); - ASSERT_TRUE(scrollLayer); - - webScrollLayer = scrollLayer->platformLayer(); - ASSERT_TRUE(webScrollLayer->scrollable()); - ASSERT_FALSE( - webScrollLayer->mainThreadScrollingReasons() & - MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects); + scrollLayer = layoutObject->frameView() + ->layoutViewportScrollableArea() + ->layerForScrolling(); + if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) { + // When RLS is enabled, the LayoutView won't have a scrolling contents + // because it does not overflow. + ASSERT_FALSE(scrollLayer); + } else { + ASSERT_TRUE(scrollLayer); + webScrollLayer = scrollLayer->platformLayer(); + ASSERT_TRUE(webScrollLayer->scrollable()); + ASSERT_FALSE( + webScrollLayer->mainThreadScrollingReasons() & + MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects); + } } class StyleRelatedMainThreadScrollingReasonTest @@ -1093,28 +1099,32 @@ } }; -TEST_F(StyleRelatedMainThreadScrollingReasonTest, TransparentTest) { +INSTANTIATE_TEST_CASE_P(All, + StyleRelatedMainThreadScrollingReasonTest, + ::testing::Bool()); + +TEST_P(StyleRelatedMainThreadScrollingReasonTest, TransparentTest) { testStyle("transparent", MainThreadScrollingReason::kHasOpacityAndLCDText); } -TEST_F(StyleRelatedMainThreadScrollingReasonTest, TransformTest) { +TEST_P(StyleRelatedMainThreadScrollingReasonTest, TransformTest) { testStyle("transform", MainThreadScrollingReason::kHasTransformAndLCDText); } -TEST_F(StyleRelatedMainThreadScrollingReasonTest, BackgroundNotOpaqueTest) { +TEST_P(StyleRelatedMainThreadScrollingReasonTest, BackgroundNotOpaqueTest) { testStyle("background-not-opaque", MainThreadScrollingReason::kBackgroundNotOpaqueInRectAndLCDText); } -TEST_F(StyleRelatedMainThreadScrollingReasonTest, BorderRadiusTest) { +TEST_P(StyleRelatedMainThreadScrollingReasonTest, BorderRadiusTest) { testStyle("border-radius", MainThreadScrollingReason::kHasBorderRadius); } -TEST_F(StyleRelatedMainThreadScrollingReasonTest, ClipTest) { +TEST_P(StyleRelatedMainThreadScrollingReasonTest, ClipTest) { testStyle("clip", MainThreadScrollingReason::kHasClipRelatedProperty); } -TEST_F(StyleRelatedMainThreadScrollingReasonTest, ClipPathTest) { +TEST_P(StyleRelatedMainThreadScrollingReasonTest, ClipPathTest) { uint32_t reason = MainThreadScrollingReason::kHasClipRelatedProperty; webViewImpl()->settings()->setPreferCompositingToLCDTextEnabled(false); Document* document = frame()->document(); @@ -1149,7 +1159,7 @@ ASSERT_FALSE(frameView->mainThreadScrollingReasons() & reason); } -TEST_F(StyleRelatedMainThreadScrollingReasonTest, LCDTextEnabledTest) { +TEST_P(StyleRelatedMainThreadScrollingReasonTest, LCDTextEnabledTest) { testStyle("transparent border-radius", MainThreadScrollingReason::kHasOpacityAndLCDText | MainThreadScrollingReason::kHasBorderRadius);
diff --git a/third_party/WebKit/Source/web/tests/TouchActionTest.cpp b/third_party/WebKit/Source/web/tests/TouchActionTest.cpp index fc096a6..1aba585 100644 --- a/third_party/WebKit/Source/web/tests/TouchActionTest.cpp +++ b/third_party/WebKit/Source/web/tests/TouchActionTest.cpp
@@ -44,9 +44,9 @@ #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebTouchEvent.h" #include "public/platform/WebURLLoaderMockFactory.h" -#include "public/web/WebCache.h" #include "public/web/WebDocument.h" #include "public/web/WebFrame.h" #include "public/web/WebHitTestResult.h"
diff --git a/third_party/WebKit/Source/web/tests/ViewportTest.cpp b/third_party/WebKit/Source/web/tests/ViewportTest.cpp index d44af20..ab03e58 100644 --- a/third_party/WebKit/Source/web/tests/ViewportTest.cpp +++ b/third_party/WebKit/Source/web/tests/ViewportTest.cpp
@@ -41,8 +41,8 @@ #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebURLLoaderMockFactory.h" -#include "public/web/WebCache.h" #include "public/web/WebConsoleMessage.h" #include "public/web/WebFrame.h" #include "public/web/WebScriptSource.h"
diff --git a/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp b/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp index 7d084c1d..e6d0688 100644 --- a/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp +++ b/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp
@@ -24,11 +24,11 @@ #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebCachePolicy.h" #include "public/platform/WebInputEvent.h" #include "public/platform/WebLayerTreeView.h" #include "public/platform/WebURLLoaderMockFactory.h" -#include "public/web/WebCache.h" #include "public/web/WebContextMenuData.h" #include "public/web/WebDocument.h" #include "public/web/WebFrameClient.h"
diff --git a/third_party/WebKit/Source/web/tests/WebDocumentSubresourceFilterTest.cpp b/third_party/WebKit/Source/web/tests/WebDocumentSubresourceFilterTest.cpp index 2d83eca..b5bd01b 100644 --- a/third_party/WebKit/Source/web/tests/WebDocumentSubresourceFilterTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebDocumentSubresourceFilterTest.cpp
@@ -9,8 +9,8 @@ #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebURLLoaderMockFactory.h" -#include "public/web/WebCache.h" #include "public/web/WebDocument.h" #include "public/web/WebElement.h" #include "public/web/WebLocalFrame.h" @@ -27,16 +27,18 @@ explicit TestDocumentSubresourceFilter(bool allowLoads) : m_allowLoads(allowLoads) {} - bool allowLoad(const WebURL& resourceUrl, - WebURLRequest::RequestContext) override { + LoadPolicy getLoadPolicy(const WebURL& resourceUrl, + WebURLRequest::RequestContext) override { std::string resourcePath = WebString(KURL(resourceUrl).path()).utf8(); if (std::find(m_queriedSubresourcePaths.begin(), m_queriedSubresourcePaths.end(), resourcePath) == m_queriedSubresourcePaths.end()) m_queriedSubresourcePaths.push_back(resourcePath); - return m_allowLoads; + return m_allowLoads ? Allow : Disallow; } + void reportDisallowedLoad() override {} + const std::vector<std::string>& queriedSubresourcePaths() const { return m_queriedSubresourcePaths; } @@ -49,14 +51,13 @@ class SubresourceFilteringWebFrameClient : public FrameTestHelpers::TestWebFrameClient { public: - void didStartProvisionalLoad(WebLocalFrame* localFrame) override { + void didStartProvisionalLoad(WebDataSource* dataSource) override { // Normally, the filter should be set when the load is committed. For // the sake of this test, however, inject it earlier to verify that it // is not consulted for the main resource load. m_subresourceFilter = new TestDocumentSubresourceFilter(m_allowSubresourcesFromNextLoad); - localFrame->provisionalDataSource()->setSubresourceFilter( - m_subresourceFilter); + dataSource->setSubresourceFilter(m_subresourceFilter); } void setAllowSubresourcesFromNextLoad(bool allow) {
diff --git a/third_party/WebKit/Source/web/tests/WebFrameSerializerTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameSerializerTest.cpp index 5d4233e..66be9165 100644 --- a/third_party/WebKit/Source/web/tests/WebFrameSerializerTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebFrameSerializerTest.cpp
@@ -35,10 +35,10 @@ #include "platform/weborigin/KURL.h" #include "public/platform/Platform.h" #include "public/platform/WebCString.h" +#include "public/platform/WebCache.h" #include "public/platform/WebString.h" #include "public/platform/WebURL.h" #include "public/platform/WebURLLoaderMockFactory.h" -#include "public/web/WebCache.h" #include "public/web/WebFrameSerializerClient.h" #include "testing/gtest/include/gtest/gtest.h" #include "web/WebLocalFrameImpl.h"
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp index 1d4b2d7f..2056909 100644 --- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -30,6 +30,10 @@ #include "public/web/WebFrame.h" +#include <stdarg.h> +#include <v8.h> +#include <map> +#include <memory> #include "SkBitmap.h" #include "SkCanvas.h" #include "bindings/core/v8/SerializedScriptValueFactory.h" @@ -99,6 +103,7 @@ #include "platform/weborigin/SchemeRegistry.h" #include "platform/weborigin/SecurityOrigin.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebCachePolicy.h" #include "public/platform/WebClipboard.h" #include "public/platform/WebFloatRect.h" @@ -109,7 +114,6 @@ #include "public/platform/WebURLLoaderClient.h" #include "public/platform/WebURLLoaderMockFactory.h" #include "public/platform/WebURLResponse.h" -#include "public/web/WebCache.h" #include "public/web/WebConsoleMessage.h" #include "public/web/WebDataSource.h" #include "public/web/WebDeviceEmulationParams.h" @@ -143,10 +147,6 @@ #include "wtf/Forward.h" #include "wtf/PtrUtil.h" #include "wtf/dtoa/utils.h" -#include <map> -#include <memory> -#include <stdarg.h> -#include <v8.h> using blink::URLTestHelpers::toKURL; using blink::testing::runPendingTasks; @@ -7346,21 +7346,16 @@ public: TestHistoryWebFrameClient() { m_replacesCurrentHistoryItem = false; - m_frame = nullptr; } - void didStartProvisionalLoad(WebLocalFrame* frame) { - WebDataSource* ds = frame->provisionalDataSource(); - m_replacesCurrentHistoryItem = ds->replacesCurrentHistoryItem(); - m_frame = frame; + void didStartProvisionalLoad(WebDataSource* dataSource) { + m_replacesCurrentHistoryItem = dataSource->replacesCurrentHistoryItem(); } bool replacesCurrentHistoryItem() { return m_replacesCurrentHistoryItem; } - WebFrame* frame() { return m_frame; } private: bool m_replacesCurrentHistoryItem; - WebFrame* m_frame; }; // Tests that the first navigation in an initially blank subframe will result in @@ -7380,17 +7375,14 @@ WebFrame* iframe = frame->firstChild(); ASSERT_EQ(&client, toWebLocalFrameImpl(iframe)->client()); - EXPECT_EQ(iframe, client.frame()); std::string url1 = m_baseURL + "history.html"; FrameTestHelpers::loadFrame(iframe, url1); - EXPECT_EQ(iframe, client.frame()); EXPECT_EQ(url1, iframe->document().url().string().utf8()); EXPECT_TRUE(client.replacesCurrentHistoryItem()); std::string url2 = m_baseURL + "find.html"; FrameTestHelpers::loadFrame(iframe, url2); - EXPECT_EQ(iframe, client.frame()); EXPECT_EQ(url2, iframe->document().url().string().utf8()); EXPECT_FALSE(client.replacesCurrentHistoryItem()); } @@ -7417,12 +7409,10 @@ "document.body.appendChild(f)"); WebFrame* iframe = frame->firstChild(); - EXPECT_EQ(iframe, client.frame()); EXPECT_EQ(url1, iframe->document().url().string().utf8()); std::string url2 = m_baseURL + "find.html"; FrameTestHelpers::loadFrame(iframe, url2); - EXPECT_EQ(iframe, client.frame()); EXPECT_EQ(url2, iframe->document().url().string().utf8()); EXPECT_FALSE(client.replacesCurrentHistoryItem()); } @@ -7759,6 +7749,16 @@ webViewHelper.resize(WebSize(viewportWidth, viewportHeight)); webViewImpl->updateAllLifecyclePhases(); + WebLayer* webScrollLayer = webViewImpl->mainFrameImpl() + ->frame() + ->view() + ->layoutViewportScrollableArea() + ->layerForScrolling() + ->platformLayer(); + ASSERT_TRUE(webScrollLayer->scrollable()); + ASSERT_TRUE(webScrollLayer->userScrollableHorizontal()); + ASSERT_TRUE(webScrollLayer->userScrollableVertical()); + Document* document = webViewImpl->mainFrameImpl()->frame()->document(); UserGestureIndicator gesture(DocumentUserGestureToken::create(document)); Fullscreen::requestFullscreen(*document->documentElement()); @@ -7778,8 +7778,12 @@ Fullscreen::fullscreenElementFrom(*document)); // Verify that the main frame is still scrollable. - WebLayer* webScrollLayer = - webViewImpl->compositor()->scrollLayer()->platformLayer(); + webScrollLayer = webViewImpl->mainFrameImpl() + ->frame() + ->view() + ->layoutViewportScrollableArea() + ->layerForScrolling() + ->platformLayer(); ASSERT_TRUE(webScrollLayer->scrollable()); ASSERT_TRUE(webScrollLayer->userScrollableHorizontal()); ASSERT_TRUE(webScrollLayer->userScrollableVertical()); @@ -8470,7 +8474,7 @@ void reset() { m_webViewHelper.reset(); } WebFrame* mainFrame() const { return m_webViewHelper.webView()->mainFrame(); } - WebView* webView() const { return m_webViewHelper.webView(); } + WebViewImpl* webView() const { return m_webViewHelper.webView(); } private: FrameTestHelpers::WebViewHelper m_webViewHelper; @@ -8816,6 +8820,40 @@ reset(); } +TEST_F(WebFrameSwapTest, SetTimeoutAfterSwap) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + mainFrame()->executeScript( + WebScriptSource("savedSetTimeout = window[0].setTimeout")); + + // Swap the frame to a remote frame. + FrameTestHelpers::TestWebRemoteFrameClient remoteClient; + WebRemoteFrame* remoteFrame = remoteClient.frame(); + WebFrame* targetFrame = mainFrame()->firstChild(); + targetFrame->swap(remoteFrame); + remoteFrame->setReplicatedOrigin(SecurityOrigin::createUnique()); + + // Invoking setTimeout should throw a security error. + { + v8::Local<v8::Value> exception = mainFrame()->executeScriptAndReturnValue( + WebScriptSource("try {\n" + " savedSetTimeout.call(window[0], () => {}, 0);\n" + "} catch (e) { e; }")); + ASSERT_TRUE(!exception.IsEmpty()); + EXPECT_EQ( + "SecurityError: Failed to execute 'setTimeout' on 'Window': Blocked a " + "frame with origin \"http://internal.test\" from accessing a " + "cross-origin frame.", + toCoreString(exception + ->ToString(ScriptState::forMainWorld( + webView()->mainFrameImpl()->frame()) + ->context()) + .ToLocalChecked())); + } + + reset(); +} + TEST_F(WebFrameSwapTest, SwapInitializesGlobal) { v8::HandleScope scope(v8::Isolate::GetCurrent()); @@ -10075,7 +10113,7 @@ EXPECT_EQ(0, m_callbackCount++); FrameTestHelpers::TestWebFrameClient::didStartLoading(toDifferentDocument); } - void didStartProvisionalLoad(WebLocalFrame*) override { + void didStartProvisionalLoad(WebDataSource*) override { EXPECT_EQ(1, m_callbackCount++); } void didCommitProvisionalLoad(WebLocalFrame*,
diff --git a/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp b/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp index 909e304..1e28cd25 100644 --- a/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp
@@ -48,13 +48,13 @@ #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebClipboard.h" #include "public/platform/WebCompositorSupport.h" #include "public/platform/WebLayer.h" #include "public/platform/WebMouseWheelEvent.h" #include "public/platform/WebThread.h" #include "public/platform/WebURLLoaderMockFactory.h" -#include "public/web/WebCache.h" #include "public/web/WebDocument.h" #include "public/web/WebElement.h" #include "public/web/WebFrame.h"
diff --git a/third_party/WebKit/Source/web/tests/WebSearchableFormDataTest.cpp b/third_party/WebKit/Source/web/tests/WebSearchableFormDataTest.cpp index c9d1ef5..32bad6d 100644 --- a/third_party/WebKit/Source/web/tests/WebSearchableFormDataTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebSearchableFormDataTest.cpp
@@ -33,8 +33,8 @@ #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebURLLoaderMockFactory.h" -#include "public/web/WebCache.h" #include "public/web/WebDocument.h" #include "public/web/WebFrame.h" #include "testing/gmock/include/gmock/gmock.h"
diff --git a/third_party/WebKit/Source/web/tests/WebViewTest.cpp b/third_party/WebKit/Source/web/tests/WebViewTest.cpp index 498765c..add6983 100644 --- a/third_party/WebKit/Source/web/tests/WebViewTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebViewTest.cpp
@@ -30,6 +30,7 @@ #include "public/web/WebView.h" +#include <memory> #include "bindings/core/v8/V8Document.h" #include "core/dom/Document.h" #include "core/dom/DocumentUserGestureToken.h" @@ -68,6 +69,7 @@ #include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" +#include "public/platform/WebCache.h" #include "public/platform/WebDisplayMode.h" #include "public/platform/WebDragData.h" #include "public/platform/WebDragOperation.h" @@ -80,7 +82,6 @@ #include "public/platform/WebThread.h" #include "public/platform/WebURLLoaderMockFactory.h" #include "public/web/WebAutofillClient.h" -#include "public/web/WebCache.h" #include "public/web/WebDateTimeChooserCompletion.h" #include "public/web/WebDeviceEmulationParams.h" #include "public/web/WebDocument.h" @@ -107,7 +108,6 @@ #include "web/WebViewImpl.h" #include "web/tests/FrameTestHelpers.h" #include "wtf/PtrUtil.h" -#include <memory> #if OS(MACOSX) #include "public/web/mac/WebSubstringUtil.h" @@ -1550,8 +1550,9 @@ EXPECT_EQ("hello world", std::string(info.value.utf8().data())); EXPECT_EQ(2, info.selectionStart); EXPECT_EQ(2, info.selectionEnd); - EXPECT_EQ(-1, info.compositionStart); - EXPECT_EQ(-1, info.compositionEnd); + // Composition range should be reset by browser process or keyboard apps. + EXPECT_EQ(6, info.compositionStart); + EXPECT_EQ(11, info.compositionEnd); } TEST_P(WebViewTest, IsSelectionAnchorFirst) { @@ -2344,6 +2345,41 @@ EXPECT_EQ("testword", std::string(frame->selectionAsText().utf8().data())); } +TEST_P(WebViewTest, FinishComposingTextDoesNotDismissHandles) { + registerMockedHttpURLLoad("longpress_selection.html"); + + WebViewImpl* webView = m_webViewHelper.initializeAndLoad( + m_baseURL + "longpress_selection.html", true); + webView->resize(WebSize(500, 300)); + webView->updateAllLifecyclePhases(); + runPendingTasks(); + + WebString target = WebString::fromUTF8("target"); + WebLocalFrameImpl* frame = webView->mainFrameImpl(); + WebInputMethodController* activeInputMethodController = + frame->frameWidget()->getActiveWebInputMethodController(); + EXPECT_TRUE(tapElementById(WebInputEvent::GestureTap, target)); + WebVector<WebCompositionUnderline> emptyUnderlines; + frame->setEditableSelectionOffsets(8, 8); + EXPECT_TRUE(activeInputMethodController->setComposition( + "12345", emptyUnderlines, 8, 13)); + EXPECT_TRUE(frame->frame()->inputMethodController().hasComposition()); + EXPECT_EQ("", std::string(frame->selectionAsText().utf8().data())); + EXPECT_FALSE(frame->frame()->selection().isHandleVisible()); + EXPECT_TRUE(frame->frame()->inputMethodController().hasComposition()); + + EXPECT_TRUE(tapElementById(WebInputEvent::GestureLongPress, target)); + EXPECT_EQ("testword12345", + std::string(frame->selectionAsText().utf8().data())); + EXPECT_TRUE(frame->frame()->selection().isHandleVisible()); + EXPECT_TRUE(frame->frame()->inputMethodController().hasComposition()); + + // Check that finishComposingText(KeepSelection) does not dismiss handles. + activeInputMethodController->finishComposingText( + WebInputMethodController::KeepSelection); + EXPECT_TRUE(frame->frame()->selection().isHandleVisible()); +} + #if !OS(MACOSX) TEST_P(WebViewTest, TouchDoesntSelectEmptyTextarea) { registerMockedHttpURLLoad("longpress_textarea.html"); @@ -3043,15 +3079,14 @@ "10,000,000won</div>"; WebString clipText; WebString clipHtml; - WebRect clipRect; registerMockedHttpURLLoad("Ahem.ttf"); registerMockedHttpURLLoad("smartclip.html"); - WebView* webView = + WebViewImpl* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "smartclip.html"); webView->resize(WebSize(500, 500)); webView->updateAllLifecyclePhases(); WebRect cropRect(300, 125, 152, 50); - webView->extractSmartClipData(cropRect, clipText, clipHtml, clipRect); + webView->mainFrameImpl()->extractSmartClipData(cropRect, clipText, clipHtml); EXPECT_STREQ(kExpectedClipText, clipText.utf8().c_str()); EXPECT_STREQ(kExpectedClipHtml, clipHtml.utf8().c_str()); } @@ -3079,17 +3114,16 @@ "10,000,000won</div>"; WebString clipText; WebString clipHtml; - WebRect clipRect; registerMockedHttpURLLoad("Ahem.ttf"); registerMockedHttpURLLoad("smartclip.html"); - WebView* webView = + WebViewImpl* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "smartclip.html"); webView->resize(WebSize(500, 500)); webView->updateAllLifecyclePhases(); webView->setPageScaleFactor(1.5); webView->setVisualViewportOffset(WebFloatPoint(167, 100)); WebRect cropRect(200, 38, 228, 75); - webView->extractSmartClipData(cropRect, clipText, clipHtml, clipRect); + webView->mainFrameImpl()->extractSmartClipData(cropRect, clipText, clipHtml); EXPECT_STREQ(kExpectedClipText, clipText.utf8().c_str()); EXPECT_STREQ(kExpectedClipHtml, clipHtml.utf8().c_str()); } @@ -3097,15 +3131,14 @@ TEST_P(WebViewTest, SmartClipReturnsEmptyStringsWhenUserSelectIsNone) { WebString clipText; WebString clipHtml; - WebRect clipRect; registerMockedHttpURLLoad("Ahem.ttf"); registerMockedHttpURLLoad("smartclip_user_select_none.html"); - WebView* webView = m_webViewHelper.initializeAndLoad( + WebViewImpl* webView = m_webViewHelper.initializeAndLoad( m_baseURL + "smartclip_user_select_none.html"); webView->resize(WebSize(500, 500)); webView->updateAllLifecyclePhases(); WebRect cropRect(0, 0, 100, 100); - webView->extractSmartClipData(cropRect, clipText, clipHtml, clipRect); + webView->mainFrameImpl()->extractSmartClipData(cropRect, clipText, clipHtml); EXPECT_STREQ("", clipText.utf8().c_str()); EXPECT_STREQ("", clipHtml.utf8().c_str()); } @@ -3113,17 +3146,16 @@ TEST_P(WebViewTest, SmartClipDoesNotCrashPositionReversed) { WebString clipText; WebString clipHtml; - WebRect clipRect; registerMockedHttpURLLoad("Ahem.ttf"); registerMockedHttpURLLoad("smartclip_reversed_positions.html"); - WebView* webView = m_webViewHelper.initializeAndLoad( + WebViewImpl* webView = m_webViewHelper.initializeAndLoad( m_baseURL + "smartclip_reversed_positions.html"); webView->resize(WebSize(500, 500)); webView->updateAllLifecyclePhases(); // Left upper corner of the rect will be end position in the DOM hierarchy. WebRect cropRect(30, 110, 400, 250); // This should not still crash. See crbug.com/589082 for more details. - webView->extractSmartClipData(cropRect, clipText, clipHtml, clipRect); + webView->mainFrameImpl()->extractSmartClipData(cropRect, clipText, clipHtml); } class CreateChildCounterFrameClient @@ -3841,14 +3873,13 @@ webView->settings()->setDefaultFontSize(12); webView->resize(WebSize(400, 400)); WebLocalFrameImpl* frame = webView->mainFrameImpl(); - FrameView* frameView = frame->frame()->view(); WebPoint baselinePoint; NSAttributedString* result = WebSubstringUtil::attributedSubstringInRange( frame, 10, 3, &baselinePoint); ASSERT_TRUE(!!result); - WebPoint point(baselinePoint.x, frameView->height() - baselinePoint.y); + WebPoint point(baselinePoint.x, baselinePoint.y); result = WebSubstringUtil::attributedWordAtPoint(frame->frameWidget(), point, baselinePoint); ASSERT_TRUE(!!result); @@ -3859,12 +3890,39 @@ WebSubstringUtil::attributedSubstringInRange(frame, 5, 5, &baselinePoint); ASSERT_TRUE(!!result); - point = WebPoint(baselinePoint.x, frameView->height() - baselinePoint.y); + point = WebPoint(baselinePoint.x, baselinePoint.y); result = WebSubstringUtil::attributedWordAtPoint(frame->frameWidget(), point, baselinePoint); ASSERT_TRUE(!!result); } +TEST_P(WebViewTest, WebSubstringUtilPinchZoom) { + registerMockedHttpURLLoad("content_editable_populated.html"); + WebViewImpl* webView = m_webViewHelper.initializeAndLoad( + m_baseURL + "content_editable_populated.html"); + webView->settings()->setDefaultFontSize(12); + webView->resize(WebSize(400, 400)); + WebLocalFrameImpl* frame = webView->mainFrameImpl(); + NSAttributedString* result = nil; + + WebPoint baselinePoint; + result = WebSubstringUtil::attributedSubstringInRange(frame, 10, 3, + &baselinePoint); + ASSERT_TRUE(!!result); + + webView->setPageScaleFactor(3); + + WebPoint pointAfterZoom; + result = WebSubstringUtil::attributedSubstringInRange(frame, 10, 3, + &pointAfterZoom); + ASSERT_TRUE(!!result); + + // We won't have moved by a full factor of 3 because of the translations, but + // we should move by a factor of >2. + EXPECT_LT(2 * baselinePoint.x, pointAfterZoom.x); + EXPECT_LT(2 * baselinePoint.y, pointAfterZoom.y); +} + TEST_P(WebViewTest, WebSubstringUtilIframe) { registerMockedHttpURLLoad("single_iframe.html"); registerMockedHttpURLLoad("visible_iframe.html"); @@ -3882,8 +3940,7 @@ childFrame, 11, 7, &baselinePoint); ASSERT_NE(result, nullptr); - WebPoint point(baselinePoint.x, - mainFrame->frameView()->height() - baselinePoint.y); + WebPoint point(baselinePoint.x, baselinePoint.y); result = WebSubstringUtil::attributedWordAtPoint(mainFrame->frameWidget(), point, baselinePoint); ASSERT_NE(result, nullptr); @@ -3899,7 +3956,7 @@ point, baselinePoint); ASSERT_NE(result, nullptr); - EXPECT_EQ(yBeforeChange, baselinePoint.y + 100); + EXPECT_EQ(yBeforeChange, baselinePoint.y - 100); } #endif
diff --git a/third_party/WebKit/Source/web/tests/data/has-non-layer-viewport-constrained-objects.html b/third_party/WebKit/Source/web/tests/data/has-non-layer-viewport-constrained-objects.html index 50796f6..f2919be 100644 --- a/third_party/WebKit/Source/web/tests/data/has-non-layer-viewport-constrained-objects.html +++ b/third_party/WebKit/Source/web/tests/data/has-non-layer-viewport-constrained-objects.html
@@ -1,4 +1,2 @@ <div style="position:fixed;">Fixed obj</div> -<div id="scrollable" style="overflow: scroll; height:200px; will-change:transform;"> - <iframe id="iframe"></iframe> -</div> +<div id="scrollable" style="overflow: scroll; height:200px; will-change:transform;"></div>
diff --git a/third_party/WebKit/Source/web/tests/data/iframe-background-attachment-fixed-inner.html b/third_party/WebKit/Source/web/tests/data/iframe-background-attachment-fixed-inner.html index 38843967..5dc4b2d 100644 --- a/third_party/WebKit/Source/web/tests/data/iframe-background-attachment-fixed-inner.html +++ b/third_party/WebKit/Source/web/tests/data/iframe-background-attachment-fixed-inner.html
@@ -3,8 +3,7 @@ .background-attachment-fixed { background-image: url("white-1x1.png"); background-attachment: fixed; - height: 2000px; } </style> -<div id="scrollable" style="will-change:transform;" class="background-attachment-fixed" /> +<div id="scrollable" style="will-change:transform; height: 2000px;" class="background-attachment-fixed" />
diff --git a/third_party/WebKit/Source/web/tests/data/longpress_selection.html b/third_party/WebKit/Source/web/tests/data/longpress_selection.html index 866994f..a827668 100644 --- a/third_party/WebKit/Source/web/tests/data/longpress_selection.html +++ b/third_party/WebKit/Source/web/tests/data/longpress_selection.html
@@ -9,7 +9,7 @@ </head> <body> Hello this is some text for testing. Here is a -<span id="target"> +<span id="target" contenteditable> testword </span> that we should be able to select by longpressing.
diff --git a/third_party/WebKit/Source/web/tests/sim/SimTest.cpp b/third_party/WebKit/Source/web/tests/sim/SimTest.cpp index 8350a076..0ec6383 100644 --- a/third_party/WebKit/Source/web/tests/sim/SimTest.cpp +++ b/third_party/WebKit/Source/web/tests/sim/SimTest.cpp
@@ -9,7 +9,7 @@ #include "platform/LayoutTestSupport.h" #include "platform/scroll/ScrollbarTheme.h" #include "platform/testing/UnitTestHelpers.h" -#include "public/web/WebCache.h" +#include "public/platform/WebCache.h" #include "web/WebLocalFrameImpl.h" #include "web/WebViewImpl.h"
diff --git a/third_party/WebKit/Source/wtf/StaticConstructors.h b/third_party/WebKit/Source/wtf/StaticConstructors.h index a12b548..bf4d377d 100644 --- a/third_party/WebKit/Source/wtf/StaticConstructors.h +++ b/third_party/WebKit/Source/wtf/StaticConstructors.h
@@ -32,7 +32,7 @@ // Use an array of pointers instead of an array of char in case there is some // alignment issue. -#define DEFINE_GLOBAL(type, name, ...) \ +#define DEFINE_GLOBAL(type, name) \ void* name##Storage[(sizeof(type) + sizeof(void*) - 1) / sizeof(void*)]; \ const type& name = *reinterpret_cast<type*>(&name##Storage)
diff --git a/third_party/WebKit/Source/wtf/WTF.cpp b/third_party/WebKit/Source/wtf/WTF.cpp index 5fb8a67..f6d29b56 100644 --- a/third_party/WebKit/Source/wtf/WTF.cpp +++ b/third_party/WebKit/Source/wtf/WTF.cpp
@@ -43,7 +43,6 @@ extern void initializeThreading(); bool s_initialized; -bool s_shutdown; void (*s_callOnMainThreadFunction)(MainThreadFunction, void*); ThreadIdentifier s_mainThreadIdentifier; @@ -60,10 +59,9 @@ } void initialize(void (*callOnMainThreadFunction)(MainThreadFunction, void*)) { - // WTF, and Blink in general, cannot handle being re-initialized, even if - // shutdown first. Make that explicit here. + // WTF, and Blink in general, cannot handle being re-initialized. + // Make that explicit here. RELEASE_ASSERT(!s_initialized); - RELEASE_ASSERT(!s_shutdown); s_initialized = true; initializeThreading(); @@ -73,14 +71,4 @@ StringStatics::init(); } -void shutdown() { - RELEASE_ASSERT(s_initialized); - RELEASE_ASSERT(!s_shutdown); - s_shutdown = true; -} - -bool isShutdown() { - return s_shutdown; -} - } // namespace WTF
diff --git a/third_party/WebKit/Source/wtf/WTF.h b/third_party/WebKit/Source/wtf/WTF.h index dbb70826..ad4311d 100644 --- a/third_party/WebKit/Source/wtf/WTF.h +++ b/third_party/WebKit/Source/wtf/WTF.h
@@ -41,8 +41,6 @@ // This function must be called exactly once from the main thread before using // anything else in WTF. WTF_EXPORT void initialize(void (*)(MainThreadFunction, void*)); -WTF_EXPORT void shutdown(); -WTF_EXPORT bool isShutdown(); WTF_EXPORT bool isMainThread(); namespace internal {
diff --git a/third_party/WebKit/Tools/OWNERS b/third_party/WebKit/Tools/OWNERS index eff2537..c04522f 100644 --- a/third_party/WebKit/Tools/OWNERS +++ b/third_party/WebKit/Tools/OWNERS
@@ -2,3 +2,5 @@ jochen@chromium.org peter@chromium.org tony@chromium.org + +# COMPONENT: Blink>Infra
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git.py similarity index 100% rename from third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git.py rename to third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git.py
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git_mock.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git_mock.py similarity index 100% rename from third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git_mock.py rename to third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git_mock.py
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git_unittest.py similarity index 99% rename from third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git_unittest.py rename to third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git_unittest.py index fe9180e..cfaf1e7 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git_unittest.py
@@ -8,7 +8,7 @@ from webkitpy.common.system.executive_mock import MockExecutive from webkitpy.common.system.filesystem import FileSystem from webkitpy.common.system.filesystem_mock import MockFileSystem -from webkitpy.common.checkout.scm.git import Git +from webkitpy.common.checkout.git import Git class GitTestWithRealFilesystemAndExecutive(unittest.TestCase): @@ -33,7 +33,6 @@ self._chdir(self.tracking_git_checkout_path) self.tracking_scm = Git(cwd=self.tracking_git_checkout_path, filesystem=self.filesystem, executive=self.executive) - def tearDown(self): self._chdir(self.original_cwd) self._run(['rm', '-rf', self.tracking_git_checkout_path])
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/__init__.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/__init__.py deleted file mode 100644 index ef65bee5..0000000 --- a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/__init__.py +++ /dev/null
@@ -1 +0,0 @@ -# Required for Python to search this directory for module files
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/host.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/host.py index 8fbb7871..176237f 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/common/host.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/host.py
@@ -29,7 +29,7 @@ import logging -from webkitpy.common.checkout.scm.git import Git +from webkitpy.common.checkout.git import Git from webkitpy.common.config.builders import BUILDERS from webkitpy.common.net import web from webkitpy.common.net.buildbot import BuildBot
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/host_mock.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/host_mock.py index b204e2d2..1246a1d 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/common/host_mock.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/host_mock.py
@@ -27,7 +27,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. from webkitpy.common.config.builders import BUILDERS -from webkitpy.common.checkout.scm.git_mock import MockGit +from webkitpy.common.checkout.git_mock import MockGit from webkitpy.common.net.buildbot_mock import MockBuildBot from webkitpy.common.net.web_mock import MockWeb from webkitpy.common.system.system_host_mock import MockSystemHost
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/web_mock.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/web_mock.py index 6e75ab2..e20fe9c7 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/web_mock.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/web_mock.py
@@ -40,20 +40,3 @@ if url in self.urls: return self.urls[url] return "MOCK Web result, convert 404 to None=%s" % return_none_on_404 - - -# FIXME: Classes which are using Browser probably want to use Web instead. -class MockBrowser(object): - params = {} - - def open(self, url): - pass - - def select_form(self, name): - pass - - def __setitem__(self, key, value): - self.params[key] = value - - def submit(self): - return StringIO.StringIO()
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py index e570bdc..fe2531a9 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py
@@ -58,14 +58,6 @@ json_results_generator._JSON_PREFIX + json + json_results_generator._JSON_SUFFIX), json) self.assertEqual(json_results_generator.strip_json_wrapper(json), json) - def _find_test_in_trie(self, path, trie): - nodes = path.split("/") - sub_trie = trie - for node in nodes: - self.assertIn(node, sub_trie) - sub_trie = sub_trie[node] - return sub_trie - def test_test_timings_trie(self): individual_test_timings = [] individual_test_timings.append(json_results_generator.TestResult('foo/bar/baz.html', elapsed_time=1.2))
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py index 2cf04c6..6d1aee2 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py
@@ -971,10 +971,6 @@ return expected_results @staticmethod - def has_pixel_failures(actual_results): - return IMAGE in actual_results or FAIL in actual_results - - @staticmethod def suffixes_for_expectations(expectations): suffixes = set() if IMAGE in expectations:
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 3c47281..329d27cd 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
@@ -343,10 +343,6 @@ return False return True - def _check_port_build(self): - # Ports can override this method to do additional checks. - return True - def check_sys_deps(self, needs_http): """Checks whether the system is properly configured. @@ -1262,9 +1258,6 @@ test_configurations.append(TestConfiguration(version, architecture, build_type)) return test_configurations - def warn_if_bug_missing_in_test_expectations(self): - return True - def _flag_specific_expectations_files(self): return [self._filesystem.join(self.layout_tests_dir(), 'FlagExpectations', flag.lstrip('-')) for flag in self.get_option('additional_driver_flag', [])] @@ -1650,11 +1643,6 @@ pass return True - def _chromium_baseline_path(self, platform): - if platform is None: - platform = self.name() - return self.path_from_webkit_base('LayoutTests', 'platform', platform) - class VirtualTestSuite(object):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py index 7ef3b78..fd8fb7c 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py
@@ -54,12 +54,6 @@ return TestPort(host, **kwargs) return Port(host, port_name or 'baseport', **kwargs) - def _file_with_contents(self, contents, encoding="utf-8"): - new_file = tempfile.NamedTemporaryFile() - new_file.write(contents.encode(encoding)) - new_file.flush() - return new_file - def test_pretty_patch_os_error(self): port = self.make_port(executive=MockExecutive(exception=OSError)) oc = OutputCapture()
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/linux.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/linux.py index d78ae0b..60a6863 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/linux.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/linux.py
@@ -142,14 +142,6 @@ self._filesystem.rmtree(dummy_home) self.host.environ['HOME'] = self._original_home - def _check_apache_install(self): - result = self._check_file_exists(self.path_to_apache(), "apache2") - result = self._check_file_exists(self.path_to_apache_config_file(), "apache2 config file") and result - if not result: - _log.error(' Please install using: "sudo apt-get install apache2 libapache2-mod-php5"') - _log.error('') - return result - def _path_to_driver(self, target=None): binary_name = self.driver_name() return self._build_path_with_target(target, binary_name)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py index d51c1205..f05e102 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py
@@ -139,27 +139,6 @@ self.assertTrue('--foo=bar' in cmd_line) self.assertTrue('--foo=baz' in cmd_line) - def assert_servers_are_down(self, host, ports): - for port in ports: - try: - test_socket = socket.socket() - test_socket.connect((host, port)) - self.fail() - except IOError as error: - self.assertTrue(error.errno in (errno.ECONNREFUSED, errno.ECONNRESET)) - finally: - test_socket.close() - - def assert_servers_are_up(self, host, ports): - for port in ports: - try: - test_socket = socket.socket() - test_socket.connect((host, port)) - except IOError: - self.fail('failed to connect to %s:%d' % (host, port)) - finally: - test_socket.close() - def test_diff_image__missing_both(self): port = self.make_port() self.assertEqual(port.diff_image(None, None), (None, None))
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/server_process_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/server_process_unittest.py index 3e69c34..91a8f17 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/server_process_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/server_process_unittest.py
@@ -46,9 +46,6 @@ def results_directory(self): return "/mock-results" - def process_kill_time(self): - return 1 - class MockFile(object):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/win.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/win.py index 8d6cabd..5a22b8e0 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/win.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/win.py
@@ -174,11 +174,6 @@ self._executive.run_command([setup_mount]) # Paths are all absolute, so this does not require a cwd. return env - def _modules_to_search_for_symbols(self): - # FIXME: we should return the path to the ffmpeg equivalents to detect if we have the mp3 and aac codecs installed. - # See https://bugs.webkit.org/show_bug.cgi?id=89706. - return [] - def check_build(self, needs_http, printer): result = super(WinPort, self).check_build(needs_http, printer)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py index 9062ff4..74e1deb 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
@@ -165,9 +165,6 @@ def assertContains(self, stream, string): self.assertIn(string, stream.getvalue()) - def assertEmpty(self, stream): - self.assertFalse(stream.getvalue()) - def assertNotEmpty(self, stream): self.assertTrue(stream.getvalue()) @@ -958,10 +955,6 @@ self.assertTrue(passing_run(['--additional-expectations', '/tmp/overrides.txt', 'failures/unexpected/mismatch.html'], tests_included=True, host=host)) - @staticmethod - def has_test_of_type(tests, type): - return [test for test in tests if type in test] - def test_platform_directories_ignored_when_searching_for_tests(self): tests_run = get_tests_run(['--platform', 'test-mac-mac10.10']) self.assertNotIn('platform/test-mac-mac10.10/http/test.html', tests_run)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/update_test_expectations.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/update_test_expectations.py index 5d60a28..132b8bd1 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/update_test_expectations.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/update_test_expectations.py
@@ -104,6 +104,11 @@ if not self._has_pass_expectation(expectations): return False + # Don't check lines that have expectations for directories, since + # the flakiness of all sub-tests isn't as easy to check. + if self._is_directory(test_expectation_line.path): + return False + # The line can be deleted if the only expectation on the line that appears in the actual # results is the PASS expectation. builders_checked = [] @@ -191,6 +196,12 @@ 'SKIP') return any(s in expectations for s in unstrippable_expectations) + def _is_directory(self, path): + """Checks whether a path relative to the layout tests directory is a directory.""" + filesystem = self._host.filesystem + abs_path = filesystem.join(self._port.layout_tests_dir(), path) + return filesystem.isdir(abs_path) + def _get_builder_results_by_path(self): """Returns a dictionary of results for each builder.
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/update_test_expectations_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/update_test_expectations_unittest.py index 58559780..b936f50 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/update_test_expectations_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/update_test_expectations_unittest.py
@@ -37,20 +37,20 @@ For example, if the bot results for mytest.html are: PASS PASS FAIL PASS TIMEOUT - then _all_results_by_builder would be: + then |all_results_by_builder| would be: { 'WebKit Linux Trusty' : { 'mytest.html': ['FAIL', 'PASS', 'TIMEOUT'] } } """ - self._all_results_by_builder = {} + self.all_results_by_builder = {} def expectations_for_builder(self, builder): - if builder not in self._all_results_by_builder: + if builder not in self.all_results_by_builder: return None - return FakeBotTestExpectations(self._all_results_by_builder[builder]) + return FakeBotTestExpectations(self.all_results_by_builder[builder]) class FakePortFactory(PortFactory): @@ -180,7 +180,38 @@ self._port.all_systems = (('trusty', 'x86_64'),) self._parse_expectations(test_expectations_before) - self._expectation_factory._all_results_by_builder = { + self._expectation_factory.all_results_by_builder = { + 'WebKit Linux Trusty': { + "test/a.html": ["PASS", "PASS"], + "test/b.html": ["PASS", "PASS"], + "test/c.html": ["PASS", "PASS"], + "test/d.html": ["PASS", "PASS"], + "test/e.html": ["PASS", "PASS"], + "test/f.html": ["PASS", "PASS"], + } + } + updated_expectations = ( + self._flake_remover.get_updated_test_expectations()) + self._assert_expectations_match( + updated_expectations, test_expectations_before) + + def test_dont_remove_directory(self): + """Tests that lines with directories are untouched.""" + test_expectations_before = """ + # This expectation is for a whole directory. + Bug(test) test/ [ Failure Pass ]""" + + self._define_builders({ + "WebKit Linux Trusty": { + "port_name": "linux-trusty", + "specifiers": ['Trusty', 'Release'] + }, + }) + self._port.all_build_types = ('release',) + self._port.all_systems = (('trusty', 'x86_64'),) + + self._parse_expectations(test_expectations_before) + self._expectation_factory.all_results_by_builder = { 'WebKit Linux Trusty': { "test/a.html": ["PASS", "PASS"], "test/b.html": ["PASS", "PASS"], @@ -218,7 +249,7 @@ self._port.all_systems = (('trusty', 'x86_64'),) self._parse_expectations(test_expectations_before) - self._expectation_factory._all_results_by_builder = { + self._expectation_factory.all_results_by_builder = { 'WebKit Linux Trusty': { "test/a.html": ["PASS", "PASS"], "test/b.html": ["PASS", "IMAGE"], @@ -248,7 +279,7 @@ self._port.all_systems = (('trusty', 'x86_64'),) self._parse_expectations(test_expectations_before) - self._expectation_factory._all_results_by_builder = { + self._expectation_factory.all_results_by_builder = { 'WebKit Linux Trusty': { "test/a.html": ["PASS", "PASS"], "test/b.html": ["PASS", "PASS"], @@ -282,7 +313,7 @@ self._port.all_systems = (('trusty', 'x86_64'),) self._parse_expectations(test_expectations_before) - self._expectation_factory._all_results_by_builder = { + self._expectation_factory.all_results_by_builder = { 'WebKit Linux Trusty': { "test/a.html": ["PASS", "IMAGE"], "test/b.html": ["PASS", "TEXT"], @@ -326,7 +357,7 @@ self._port.all_systems = (('trusty', 'x86_64'),) self._parse_expectations(test_expectations_before) - self._expectation_factory._all_results_by_builder = { + self._expectation_factory.all_results_by_builder = { 'WebKit Linux Trusty': { "test/a.html": ["PASS", "PASS", "PASS"], "test/b.html": ["PASS", "IMAGE", "PASS"], @@ -355,7 +386,7 @@ self._port.all_systems = (('trusty', 'x86_64'),) self._parse_expectations(test_expectations_before) - self._expectation_factory._all_results_by_builder = { + self._expectation_factory.all_results_by_builder = { 'WebKit Linux Trusty': { "test/a.html": ["IMAGE", "IMAGE", "IMAGE"], } @@ -380,7 +411,7 @@ self._port.all_systems = (('trusty', 'x86_64'),) self._parse_expectations(test_expectations_before) - self._expectation_factory._all_results_by_builder = { + self._expectation_factory.all_results_by_builder = { 'WebKit Linux Trusty': { "test/a.html": ["PASS", "PASS", "PASS"], } @@ -415,7 +446,7 @@ ('trusty', 'x86_64')) self._parse_expectations(test_expectations_before) - self._expectation_factory._all_results_by_builder = { + self._expectation_factory.all_results_by_builder = { 'WebKit Linux Trusty': { "test/a.html": ["PASS", "PASS", "PASS"], "test/b.html": ["PASS", "PASS", "PASS"], @@ -467,7 +498,7 @@ ('trusty', 'x86_64')) self._parse_expectations(test_expectations_before) - self._expectation_factory._all_results_by_builder = { + self._expectation_factory.all_results_by_builder = { 'WebKit Linux Trusty': { "test/a.html": ["PASS", "PASS", "PASS"], "test/b.html": ["PASS", "PASS", "PASS"], @@ -532,7 +563,7 @@ ('trusty', 'x86_64')) self._parse_expectations(test_expectations_before) - self._expectation_factory._all_results_by_builder = { + self._expectation_factory.all_results_by_builder = { 'WebKit Linux Trusty': { "test/a.html": ["PASS", "PASS", "PASS"], "test/b.html": ["PASS", "IMAGE", "PASS"], @@ -621,7 +652,7 @@ self._port.all_systems = (('trusty', 'x86_64'),) self._parse_expectations(test_expectations_before) - self._expectation_factory._all_results_by_builder = { + self._expectation_factory.all_results_by_builder = { 'WebKit Linux Trusty': { "test/a.html": ["PASS", "PASS", "PASS"], "test/b.html": ["PASS", "PASS", "PASS"], @@ -671,7 +702,7 @@ self._port.all_systems = (('trusty', 'x86_64'),) self._parse_expectations(test_expectations_before) - self._expectation_factory._all_results_by_builder = { + self._expectation_factory.all_results_by_builder = { 'WebKit Linux Trusty': { } } @@ -731,7 +762,7 @@ ) self._parse_expectations(test_expectations_before) - self._expectation_factory._all_results_by_builder = { + self._expectation_factory.all_results_by_builder = { 'WebKit Linux Trusty': { "test/a.html": ["PASS", "PASS", "PASS"], "test/b.html": ["PASS", "PASS", "PASS"], @@ -816,7 +847,7 @@ ('trusty', 'x86_64')) self._parse_expectations(test_expectations_before) - self._expectation_factory._all_results_by_builder = { + self._expectation_factory.all_results_by_builder = { 'WebKit Linux Trusty': { "test/a.html": ["PASS", "PASS", "PASS"], "test/b.html": ["PASS", "IMAGE", "PASS"], @@ -886,7 +917,7 @@ # Write out the fake builder bot results. expectation_factory = FakeBotTestExpectationsFactory() - expectation_factory._all_results_by_builder = { + expectation_factory.all_results_by_builder = { 'WebKit Linux Trusty': { "test/a.html": ["PASS", "PASS", "PASS"], "test/b.html": ["PASS", "IMAGE", "PASS"], @@ -928,7 +959,7 @@ # Write out the fake builder bot results. expectation_factory = FakeBotTestExpectationsFactory() - expectation_factory._all_results_by_builder = {} + expectation_factory.all_results_by_builder = {} self.assertFalse(host.filesystem.isfile(test_expectation_path)) @@ -980,7 +1011,7 @@ # Write out the fake builder bot results. expectation_factory = FakeBotTestExpectationsFactory() - expectation_factory._all_results_by_builder = { + expectation_factory.all_results_by_builder = { 'WebKit Linux Trusty': { "test/a.html": ["PASS", "PASS", "PASS"], }, @@ -1019,7 +1050,7 @@ self._port.all_systems = (('trusty', 'x86_64'),) self._parse_expectations(test_expectations_before) - self._expectation_factory._all_results_by_builder = { + self._expectation_factory.all_results_by_builder = { 'WebKit Linux': { "test/a.html": ["PASS", "PASS", "PASS"], "test/b.html": ["PASS", "IMAGE", "PASS"],
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/buildbot_results_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/buildbot_results_unittest.py index adfb329..90294bb 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/buildbot_results_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/buildbot_results_unittest.py
@@ -37,9 +37,6 @@ class BuildBotPrinterTests(unittest.TestCase): - def assertEmpty(self, stream): - self.assertFalse(stream.getvalue()) - def assertNotEmpty(self, stream): self.assertTrue(stream.getvalue())
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/printing_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/printing_unittest.py index 0895202..58a05d5 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/printing_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/printing_unittest.py
@@ -79,9 +79,6 @@ class Testprinter(unittest.TestCase): - def assertEmpty(self, stream): - self.assertFalse(stream.getvalue()) - def assertNotEmpty(self, stream): self.assertTrue(stream.getvalue())
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/bot/commit_announcer.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/bot/commit_announcer.py index c1015eb1..415d2597 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/bot/commit_announcer.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/bot/commit_announcer.py
@@ -28,7 +28,6 @@ import threading import time -from webkitpy.common.checkout.scm.git import Git from webkitpy.common.system.executive import ScriptError from webkitpy.thirdparty.irc.ircbot import SingleServerIRCBot
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_copier.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_copier.py index f5d25a40..7e0c7712 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_copier.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_copier.py
@@ -146,13 +146,13 @@ # FIXME: This block should really be a separate function, but the early-continues make that difficult. if filename.startswith('.') or filename.endswith('.pl'): - _log.info('Skipping: %s', path_full) - _log.info(' Reason: Hidden files and perl scripts are not necessary.') + _log.debug('Skipping: %s', path_full) + _log.debug(' Reason: Hidden files and perl scripts are not necessary.') continue if filename == 'OWNERS' or filename == 'reftest.list': # See http://crbug.com/584660 and http://crbug.com/582838. - _log.info('Skipping: %s', path_full) - _log.info(' Reason: This file may cause Chromium presubmit to fail.') + _log.debug('Skipping: %s', path_full) + _log.debug(' Reason: This file may cause Chromium presubmit to fail.') continue if self.path_too_long(path_full): _log.warning('Skipping: %s', path_full)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_copier_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_copier_unittest.py index a0048c49..6631bb3 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_copier_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_copier_unittest.py
@@ -154,10 +154,6 @@ self.assertLog([ 'WARNING: Skipping: %s\n' % long_file_path, 'WARNING: Reason: Long path. Max length 140; see http://crbug.com/609871.\n', - 'INFO: Skipping: /blink/w3c/dir/reftest.list\n', - 'INFO: Reason: This file may cause Chromium presubmit to fail.\n', - 'INFO: Skipping: /blink/w3c/dir/OWNERS\n', - 'INFO: Reason: This file may cause Chromium presubmit to fail.\n', ]) def test_should_try_to_convert_positive_cases(self):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py index 6fc7e0a..45b6bb9c 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py
@@ -4,7 +4,7 @@ import collections -from webkitpy.common.checkout.scm.git_mock import MockGit +from webkitpy.common.checkout.git_mock import MockGit from webkitpy.common.host_mock import MockHost from webkitpy.common.system.executive_mock import MockExecutive from webkitpy.common.system.log_testing import LoggingTestCase
diff --git a/third_party/WebKit/Tools/Scripts/wpt-export b/third_party/WebKit/Tools/Scripts/wpt-export index 0b3e4ae..f9b3f2b 100755 --- a/third_party/WebKit/Tools/Scripts/wpt-export +++ b/third_party/WebKit/Tools/Scripts/wpt-export
@@ -11,6 +11,7 @@ """ import argparse +import json import logging from webkitpy.common.host import Host @@ -30,23 +31,34 @@ help='See what would be done without actually creating or merging ' 'any pull requests.') parser.add_argument( - '--user', + '--gh-user', help='GitHub user name. Can also be provided using the GH_USER ' 'environment variable.') parser.add_argument( - '--token', + '--gh-token', help='GitHub token or password. Can also be provided using the GH_TOKEN ' 'environment variable.') + parser.add_argument( + '--github-credentials-json', + help='A JSON file with schema {"GH_USER": "", "GH_TOKEN": ""}. ' + 'This will override credentials that were passed via command line or env var.') args = parser.parse_args() host = Host() - if not args.user: - args.user = host.environ.get('GH_USER') - if not args.token: - args.token = host.environ.get('GH_TOKEN') - if not (args.user and args.token): - parser.error('Must provide both user and token for GitHub.') - wpt_github = WPTGitHub(host, args.user, args.token) + if not args.gh_user: + args.user = host.environ.get('GH_USER') + if not args.gh_token: + args.gh_token = host.environ.get('GH_TOKEN') + if args.github_credentials_json: + with open(args.github_credentials_json, 'r') as f: + contents = json.load(f) + args.gh_user = contents['GH_USER'] + args.gh_token = contents['GH_TOKEN'] + + if not (args.gh_user and args.gh_token): + parser.error('Must provide both gh_user and gh_token for GitHub.') + + wpt_github = WPTGitHub(host, args.gh_user, args.gh_token) test_exporter = TestExporter(host, wpt_github, dry_run=args.dry_run) test_exporter.run()
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn index 6d36314..d94e4b44 100644 --- a/third_party/WebKit/public/BUILD.gn +++ b/third_party/WebKit/public/BUILD.gn
@@ -120,6 +120,7 @@ "platform/WebBlobInfo.h", "platform/WebBlobRegistry.h", "platform/WebCString.h", + "platform/WebCache.h", "platform/WebCallbacks.h", "platform/WebCanvas.h", "platform/WebCanvasCaptureHandler.h", @@ -433,7 +434,6 @@ "web/WebAutofillClient.h", "web/WebBlob.h", "web/WebCSSParser.h", - "web/WebCache.h", "web/WebColorChooser.h", "web/WebColorChooserClient.h", "web/WebColorSuggestion.h",
diff --git a/third_party/WebKit/public/blink_typemaps.gni b/third_party/WebKit/public/blink_typemaps.gni index a549c5b..0ae60711 100644 --- a/third_party/WebKit/public/blink_typemaps.gni +++ b/third_party/WebKit/public/blink_typemaps.gni
@@ -11,4 +11,5 @@ "//cc/ipc/surface_id.typemap", "//cc/ipc/surface_info.typemap", "//cc/ipc/surface_sequence.typemap", + "//gpu/ipc/common/sync_token.typemap", ]
diff --git a/third_party/WebKit/public/platform/Platform.h b/third_party/WebKit/public/platform/Platform.h index d623c5a..ffe7e912 100644 --- a/third_party/WebKit/public/platform/Platform.h +++ b/third_party/WebKit/public/platform/Platform.h
@@ -136,7 +136,6 @@ // Initialize platform and wtf. If you need to initialize the entire Blink, // you should use blink::initialize. static void initialize(Platform*); - static void shutdown(); static Platform* current(); // Used to switch the current platform only for testing.
diff --git a/third_party/WebKit/public/web/WebCache.h b/third_party/WebKit/public/platform/WebCache.h similarity index 88% rename from third_party/WebKit/public/web/WebCache.h rename to third_party/WebKit/public/platform/WebCache.h index 4fad584..0d72b8cb 100644 --- a/third_party/WebKit/public/web/WebCache.h +++ b/third_party/WebKit/public/platform/WebCache.h
@@ -31,11 +31,11 @@ #ifndef WebCache_h #define WebCache_h -#include "../platform/WebCommon.h" +#include "WebCommon.h" namespace blink { -// An interface to query and configure WebKit's resource cache. +// An interface to query and configure Blink's resource cache. class WebCache { public: struct UsageStats { @@ -61,18 +61,18 @@ }; // Sets the capacities of the resource cache, evicting objects as necessary. - BLINK_EXPORT static void setCapacity(size_t); + BLINK_PLATFORM_EXPORT static void setCapacity(size_t); // Clears the cache (as much as possible; some resources may not be // cleared if they are actively referenced). Note that this method // only removes resources from live list, w/o releasing cache memory. - BLINK_EXPORT static void clear(); + BLINK_PLATFORM_EXPORT static void clear(); // Gets the usage statistics from the resource cache. - BLINK_EXPORT static void getUsageStats(UsageStats*); + BLINK_PLATFORM_EXPORT static void getUsageStats(UsageStats*); // Get usage stats about the resource cache. - BLINK_EXPORT static void getResourceTypeStats(ResourceTypeStats*); + BLINK_PLATFORM_EXPORT static void getResourceTypeStats(ResourceTypeStats*); private: WebCache(); // Not intended to be instanced.
diff --git a/third_party/WebKit/public/platform/WebDocumentSubresourceFilter.h b/third_party/WebKit/public/platform/WebDocumentSubresourceFilter.h index 71e33d5..8bc2745f 100644 --- a/third_party/WebKit/public/platform/WebDocumentSubresourceFilter.h +++ b/third_party/WebKit/public/platform/WebDocumentSubresourceFilter.h
@@ -13,9 +13,14 @@ class WebDocumentSubresourceFilter { public: + enum LoadPolicy { Allow, Disallow, WouldDisallow }; virtual ~WebDocumentSubresourceFilter() {} - virtual bool allowLoad(const WebURL& resourceUrl, - WebURLRequest::RequestContext) = 0; + virtual LoadPolicy getLoadPolicy(const WebURL& resourceUrl, + WebURLRequest::RequestContext) = 0; + + // Report that a resource loaded by the document (not a preload) was + // disallowed. + virtual void reportDisallowedLoad() = 0; }; } // namespace blink
diff --git a/third_party/WebKit/public/platform/WebDragData.h b/third_party/WebKit/public/platform/WebDragData.h index 4eb774e0..42ce9bb 100644 --- a/third_party/WebKit/public/platform/WebDragData.h +++ b/third_party/WebKit/public/platform/WebDragData.h
@@ -62,28 +62,32 @@ StorageType storageType; + // TODO(dcheng): This should probably be a union. // Only valid when storageType == StorageTypeString. WebString stringType; WebString stringData; + // Title associated with a link when stringType == "text/uri-list". + WebString title; + + // Only valid when stringType == "text/html". Stores the base URL for the + // contained markup. + WebURL baseURL; + // Only valid when storageType == StorageTypeFilename. WebString filenameData; WebString displayNameData; // Only valid when storageType == StorageTypeBinaryData. WebData binaryData; - - // Title associated with a link when stringType == "text/uri-list". - // Filename when storageType == StorageTypeBinaryData. - WebString title; + WebURL binaryDataSourceURL; + WebString binaryDataFilenameExtension; + WebString binaryDataContentDisposition; // Only valid when storageType == StorageTypeFileSystemFile. WebURL fileSystemURL; long long fileSystemFileSize; WebString fileSystemId; - - // Only valid when stringType == "text/html". - WebURL baseURL; }; WebDragData() : m_valid(false), m_modifierKeyState(0) {}
diff --git a/third_party/WebKit/public/platform/WebLoadingBehaviorFlag.h b/third_party/WebKit/public/platform/WebLoadingBehaviorFlag.h index bcb38b3..f74eab77 100644 --- a/third_party/WebKit/public/platform/WebLoadingBehaviorFlag.h +++ b/third_party/WebKit/public/platform/WebLoadingBehaviorFlag.h
@@ -30,7 +30,10 @@ WebLoadingBehaviorCSSPreloadFound = 1 << 4, // Indicates that the page has a synchronous, same-origin document.written // script with different protocol. - WebLoadingBehaviorDocumentWriteBlockDifferentScheme = 1 << 5 + WebLoadingBehaviorDocumentWriteBlockDifferentScheme = 1 << 5, + // Indicates that a subresource on the page matched the subresource filtering + // rules. + WebLoadingBehaviorSubresourceFilterMatch = 1 << 6 }; } // namespace blink
diff --git a/third_party/WebKit/public/platform/WebURLResponse.h b/third_party/WebKit/public/platform/WebURLResponse.h index 79f275d..0db0de0 100644 --- a/third_party/WebKit/public/platform/WebURLResponse.h +++ b/third_party/WebKit/public/platform/WebURLResponse.h
@@ -174,9 +174,6 @@ BLINK_PLATFORM_EXPORT WebString textEncodingName() const; BLINK_PLATFORM_EXPORT void setTextEncodingName(const WebString&); - BLINK_PLATFORM_EXPORT WebString suggestedFileName() const; - BLINK_PLATFORM_EXPORT void setSuggestedFileName(const WebString&); - BLINK_PLATFORM_EXPORT HTTPVersion httpVersion() const; BLINK_PLATFORM_EXPORT void setHTTPVersion(HTTPVersion);
diff --git a/third_party/WebKit/public/platform/modules/budget_service/OWNERS b/third_party/WebKit/public/platform/modules/budget_service/OWNERS index 5dbf234..1fd653b 100644 --- a/third_party/WebKit/public/platform/modules/budget_service/OWNERS +++ b/third_party/WebKit/public/platform/modules/budget_service/OWNERS
@@ -2,3 +2,5 @@ per-file *.mojom=set noparent per-file *.mojom=file://ipc/SECURITY_OWNERS + +# COMPONENT: Blink>PushAPI
diff --git a/third_party/WebKit/public/platform/scheduler/test/mock_renderer_scheduler.h b/third_party/WebKit/public/platform/scheduler/test/mock_renderer_scheduler.h index 90b2b56..2dd0daf6 100644 --- a/third_party/WebKit/public/platform/scheduler/test/mock_renderer_scheduler.h +++ b/third_party/WebKit/public/platform/scheduler/test/mock_renderer_scheduler.h
@@ -6,6 +6,7 @@ #define THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_TEST_MOCK_RENDERER_SCHEDULER_H_ #include "base/macros.h" +#include "cc/output/begin_frame_args.h" #include "public/platform/scheduler/renderer/renderer_scheduler.h" #include "testing/gmock/include/gmock/gmock.h"
diff --git a/third_party/WebKit/public/web/WebFrameClient.h b/third_party/WebKit/public/web/WebFrameClient.h index c6ecc0fd..f221082 100644 --- a/third_party/WebKit/public/web/WebFrameClient.h +++ b/third_party/WebKit/public/web/WebFrameClient.h
@@ -344,7 +344,7 @@ virtual void didCreateDataSource(WebLocalFrame*, WebDataSource*) {} // A new provisional load has been started. - virtual void didStartProvisionalLoad(WebLocalFrame* localFrame) {} + virtual void didStartProvisionalLoad(WebDataSource* dataSource) {} // The provisional load was redirected via a HTTP 3xx response. virtual void didReceiveServerRedirectForProvisionalLoad(WebLocalFrame*) {}
diff --git a/third_party/WebKit/public/web/WebFrameWidget.h b/third_party/WebKit/public/web/WebFrameWidget.h index 5178df6..06ce1f3 100644 --- a/third_party/WebKit/public/web/WebFrameWidget.h +++ b/third_party/WebKit/public/web/WebFrameWidget.h
@@ -101,7 +101,8 @@ const WebPoint& screenPoint, WebDragOperationsMask operationsAllowed, int modifiers) = 0; - virtual void dragTargetDragLeave() = 0; + virtual void dragTargetDragLeave(const WebPoint& pointInViewport, + const WebPoint& screenPoint) = 0; virtual void dragTargetDrop(const WebDragData&, const WebPoint& pointInViewport, const WebPoint& screenPoint,
diff --git a/third_party/WebKit/public/web/WebKit.h b/third_party/WebKit/public/web/WebKit.h index 1a94eef0..fa3d12e 100644 --- a/third_party/WebKit/public/web/WebKit.h +++ b/third_party/WebKit/public/web/WebKit.h
@@ -48,12 +48,6 @@ // initialize must have been called first. BLINK_EXPORT v8::Isolate* mainThreadIsolate(); -// Once shutdown, the Platform passed to initialize will no longer -// be accessed. No other WebKit objects should be in use when this function is -// called. Any background threads created by WebKit are promised to be -// terminated by the time this function returns. -BLINK_EXPORT void shutdown(); - // Alters the rendering of content to conform to a fixed set of rules. BLINK_EXPORT void setLayoutTestMode(bool); BLINK_EXPORT bool layoutTestMode();
diff --git a/third_party/WebKit/public/web/WebLocalFrame.h b/third_party/WebKit/public/web/WebLocalFrame.h index 54816f8..31919e7 100644 --- a/third_party/WebKit/public/web/WebLocalFrame.h +++ b/third_party/WebKit/public/web/WebLocalFrame.h
@@ -326,6 +326,10 @@ // selection. virtual void deleteSurroundingText(int before, int after) = 0; + virtual void extractSmartClipData(WebRect rectInViewport, + WebString& clipText, + WebString& clipHtml) = 0; + // Spell-checking support ------------------------------------------------- virtual void replaceMisspelledRange(const WebString&) = 0; virtual void enableSpellChecking(bool) = 0;
diff --git a/third_party/WebKit/public/web/WebView.h b/third_party/WebKit/public/web/WebView.h index a08cf28..2701d38 100644 --- a/third_party/WebKit/public/web/WebView.h +++ b/third_party/WebKit/public/web/WebView.h
@@ -398,12 +398,6 @@ // Notify that context menu has been closed. virtual void didCloseContextMenu() = 0; - // SmartClip support --------------------------------------------------- - virtual void extractSmartClipData(WebRect initRect, - WebString& text, - WebString& html, - WebRect& resultRect) = 0; - // Popup menu ---------------------------------------------------------- // Sets whether select popup menus should be rendered by the browser.
diff --git a/third_party/WebKit/public/web/WebViewClient.h b/third_party/WebKit/public/web/WebViewClient.h index 22a7dd0..55b1cb705 100644 --- a/third_party/WebKit/public/web/WebViewClient.h +++ b/third_party/WebKit/public/web/WebViewClient.h
@@ -114,7 +114,6 @@ // These methods allow the client to intercept and overrule editing // operations. - virtual void didCancelCompositionOnSelectionChange() {} virtual void didChangeContents() {} // Dialogs -------------------------------------------------------------
diff --git a/third_party/closure_compiler/compiled_resources2.gyp b/third_party/closure_compiler/compiled_resources2.gyp index 095eb1d..bc926abe 100644 --- a/third_party/closure_compiler/compiled_resources2.gyp +++ b/third_party/closure_compiler/compiled_resources2.gyp
@@ -32,6 +32,7 @@ '<(DEPTH)/chrome/browser/resources/settings/compiled_resources2.gyp:*', '<(DEPTH)/chrome/browser/resources/uber/compiled_resources2.gyp:*', '<(DEPTH)/chrome/browser/resources/vr_shell/compiled_resources2.gyp:*', + '<(DEPTH)/chrome/browser/resources/webapks/compiled_resources2.gyp:*', '<(DEPTH)/ui/file_manager/compiled_resources2.gyp:*', '<(DEPTH)/ui/webui/resources/cr_elements/compiled_resources2.gyp:*', '<(DEPTH)/ui/webui/resources/js/chromeos/compiled_resources2.gyp:*',
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium index 726787f..6907d7d 100644 --- a/third_party/crashpad/README.chromium +++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@ Short Name: crashpad URL: https://crashpad.chromium.org/ Version: unknown -Revision: 1e4be91918b614e74a3882132fa4442e758f0e4d +Revision: 88442dd5788bf7836ab013939cca4a4683560cb0 License: Apache 2.0 License File: crashpad/LICENSE Security Critical: yes
diff --git a/third_party/crashpad/crashpad/DEPS b/third_party/crashpad/crashpad/DEPS index 7742853..db8c048c 100644 --- a/third_party/crashpad/crashpad/DEPS +++ b/third_party/crashpad/crashpad/DEPS
@@ -19,13 +19,13 @@ deps = { 'buildtools': Var('chromium_git') + '/chromium/buildtools.git@' + - 'f8fc76ea5ce4a60cda2fa5d7df3d4a62935b3113', + 'a7cc7a3e21a061975b33dcdcd81a9716ba614c3c', 'crashpad/third_party/gtest/gtest': Var('chromium_git') + '/external/github.com/google/googletest@' + - 'ec44c6c1675c25b9827aacd08c02433cccde7780', + 'd62d6c6556d96dda924382547c54a4b3afedb22c', 'crashpad/third_party/gyp/gyp': Var('chromium_git') + '/external/gyp@' + - '93cc6e2c23e4d5ebd179f388e67aa907d0dfd43d', + 'a7055b3989c1074adca03b4b4829e7f0e57f6efd', # TODO(scottmg): Consider pinning these. For now, we don't have any particular # reason to do so. @@ -38,7 +38,7 @@ 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - 'de1afb04f4afc074ec6d23bd9ee7b1e6b365427f', + '4f3cfc8e7c2b7d77f94f41a32c3ec84a6920f05d', } hooks = [ @@ -100,3 +100,7 @@ 'action': ['python', 'crashpad/build/gyp_crashpad.py'], }, ] + +recursedeps = [ + 'buildtools', +]
diff --git a/third_party/crashpad/crashpad/handler/handler_main.cc b/third_party/crashpad/crashpad/handler/handler_main.cc index 3ada8c3..9433a6a 100644 --- a/third_party/crashpad/crashpad/handler/handler_main.cc +++ b/third_party/crashpad/crashpad/handler/handler_main.cc
@@ -14,9 +14,11 @@ #include "handler/handler_main.h" +#include <errno.h> #include <getopt.h> #include <stdint.h> #include <stdlib.h> +#include <sys/types.h> #include <map> #include <memory> @@ -38,6 +40,8 @@ #include "handler/prune_crash_reports_thread.h" #include "tools/tool_support.h" #include "util/file/file_io.h" +#include "util/misc/metrics.h" +#include "util/numeric/in_range_cast.h" #include "util/stdlib/map_insert.h" #include "util/stdlib/string_number_conversion.h" #include "util/string/split_string.h" @@ -105,6 +109,122 @@ #if defined(OS_MACOSX) +struct sigaction g_original_crash_sigaction[NSIG]; + +void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) { + // Is siginfo->si_code useful? The only interesting values on macOS are 0 (not + // useful, signals generated asynchronously such as by kill() or raise()) and + // small positive numbers (useful, signal generated via a hardware fault). The + // standard specifies these other constants, and while xnu never uses them, + // they are intended to denote signals generated asynchronously and are + // included here. Additionally, existing practice on other systems + // (acknowledged by the standard) is for negative numbers to indicate that a + // signal was generated asynchronously. Although xnu does not do this, allow + // for the possibility for completeness. + bool si_code_valid = !(siginfo->si_code <= 0 || + siginfo->si_code == SI_USER || + siginfo->si_code == SI_QUEUE || + siginfo->si_code == SI_TIMER || + siginfo->si_code == SI_ASYNCIO || + siginfo->si_code == SI_MESGQ); + + // 0x5343 = 'SC', signifying “signal and code”, disambiguates from the schema + // used by ExceptionCodeForMetrics(). That system primarily uses Mach + // exception types and codes, which are not available to a POSIX signal + // handler. It does provide a way to encode only signal numbers, but does so + // with the understanding that certain “raw” signals would not be encountered + // without a Mach exception. Furthermore, it does not allow siginfo->si_code + // to be encoded, because that’s not available to Mach exception handlers. It + // would be a shame to lose that information available to a POSIX signal + // handler. + int metrics_code = 0x53430000 | (InRangeCast<uint8_t>(sig, 0xff) << 8); + if (si_code_valid) { + metrics_code |= InRangeCast<uint8_t>(siginfo->si_code, 0xff); + } + Metrics::HandlerCrashed(metrics_code); + + // Restore the previous signal handler. + DCHECK_GT(sig, 0); + DCHECK_LT(static_cast<size_t>(sig), arraysize(g_original_crash_sigaction)); + struct sigaction* osa = &g_original_crash_sigaction[sig]; + int rv = sigaction(sig, osa, nullptr); + DPLOG_IF(ERROR, rv != 0) << "sigaction " << sig; + + // If the signal was received synchronously resulting from a hardware fault, + // returning from the signal handler will cause the kernel to re-raise it, + // because this handler hasn’t done anything to alleviate the condition that + // caused the signal to be raised in the first place. With the old signal + // handler in place (expected to be SIG_DFL), it will cause the same behavior + // to be taken as though this signal handler had never been installed at all + // (expected to be a crash). This is ideal, because the signal is re-raised + // with the same properties and from the same context that initially triggered + // it, providing the best debugging experience. + + if ((sig != SIGILL && sig != SIGFPE && sig != SIGBUS && sig != SIGSEGV) || + !si_code_valid) { + // Signals received other than via hardware faults, such as those raised + // asynchronously via kill() and raise(), and those arising via hardware + // traps such as int3 (resulting in SIGTRAP but advancing the instruction + // pointer), will not reoccur on their own when returning from the signal + // handler. Re-raise them or call to the previous signal handler as + // appropriate. + // + // Unfortunately, when SIGBUS is received asynchronously via kill(), + // siginfo->si_code makes it appear as though it was actually received via a + // hardware fault. See 10.12.3 xnu-3789.41.3/bsd/dev/i386/unix_signal.c + // sendsig(). An asynchronous SIGBUS will thus cause the handler-crashed + // metric to be logged but will not cause the process to terminate. This + // isn’t ideal, but asynchronous SIGBUS is an unexpected condition. The + // alternative, to re-raise here on any SIGBUS, is a bad idea because it + // would lose properties associated with the the original signal, which are + // very valuable for debugging and are visible to a Mach exception handler. + // Since SIGBUS is normally received synchronously in response to a hardware + // fault, don’t sweat the unexpected asynchronous case. + if (osa->sa_handler == SIG_DFL) { + // Because this signal handler executes with the signal blocked, this + // raise() cannot immediately deliver the signal. Delivery is deferred + // until this signal handler returns and the signal becomes unblocked. The + // re-raised signal will appear with the same context as where it was + // initially triggered. + rv = raise(sig); + DPLOG_IF(ERROR, rv != 0) << "raise"; + } else if (osa->sa_handler != SIG_IGN) { + if (osa->sa_flags & SA_SIGINFO) { + osa->sa_sigaction(sig, siginfo, context); + } else { + osa->sa_handler(sig); + } + } + } +} + +void InstallCrashHandler() { + struct sigaction sa = {}; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = HandleCrashSignal; + + // These are the core-generating signals from 10.12.3 + // xnu-3789.41.3/bsd/sys/signalvar.h sigprop: entries with SA_CORE are in the + // set. + const int kSignals[] = {SIGQUIT, + SIGILL, + SIGTRAP, + SIGABRT, + SIGEMT, + SIGFPE, + SIGBUS, + SIGSEGV, + SIGSYS}; + + for (int sig : kSignals) { + DCHECK_GT(sig, 0); + DCHECK_LT(static_cast<size_t>(sig), arraysize(g_original_crash_sigaction)); + int rv = sigaction(sig, &sa, &g_original_crash_sigaction[sig]); + PCHECK(rv == 0) << "sigaction " << sig; + } +} + struct ResetSIGTERMTraits { static struct sigaction* InvalidValue() { return nullptr; @@ -126,9 +246,8 @@ g_exception_handler_server->Stop(); } -#endif // OS_MACOSX +#elif defined(OS_WIN) -#if defined(OS_WIN) LONG(WINAPI* g_original_exception_filter)(EXCEPTION_POINTERS*) = nullptr; LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { @@ -139,15 +258,18 @@ else return EXCEPTION_CONTINUE_SEARCH; } -#endif // OS_WIN + +void InstallCrashHandler() { + g_original_exception_filter = + SetUnhandledExceptionFilter(&UnhandledExceptionHandler); +} + +#endif // OS_MACOSX } // namespace int HandlerMain(int argc, char* argv[]) { -#if defined(OS_WIN) - g_original_exception_filter = - SetUnhandledExceptionFilter(&UnhandledExceptionHandler); -#endif + InstallCrashHandler(); const base::FilePath argv0( ToolSupport::CommandLineArgumentToFilePathStringType(argv[0]));
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_types.h b/third_party/crashpad/crashpad/snapshot/mac/process_types.h index 664b37b..7274515 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/process_types.h +++ b/third_party/crashpad/crashpad/snapshot/mac/process_types.h
@@ -27,13 +27,21 @@ namespace process_types { namespace internal { +// Some structure definitions have tail padding when built in a 64-bit +// environment, but will have less (or no) tail padding in a 32-bit environment. +// These structure’s apparent sizes will differ between these two environments, +// which is incorrect. Use this “Nothing” type to place an “end” marker after +// all of the real members of such structures, and use offsetof(type, end) to +// compute their actual sizes. +using Nothing = char[0]; + // Some structure definitions differ in 32-bit and 64-bit environments by having // additional “reserved” padding fields present only in the 64-bit environment. // These Reserved*_64Only* types allow the process_types system to replicate // these structures more precisely. -using Reserved32_64Only32 = char[0]; +using Reserved32_64Only32 = Nothing; using Reserved32_64Only64 = uint32_t; -using Reserved64_64Only32 = char[0]; +using Reserved64_64Only32 = Nothing; using Reserved64_64Only64 = uint64_t; } // namespace internal @@ -65,6 +73,7 @@ using UIntPtr = internal::TraitsGeneric::UIntPtr; \ using Reserved32_64Only = internal::TraitsGeneric::Reserved32_64Only; \ using Reserved64_64Only = internal::TraitsGeneric::Reserved64_64Only; \ + using Nothing = internal::TraitsGeneric::Nothing; \ \ /* Initializes an object with data read from |process_reader| at \ * |address|, properly genericized. */ \ @@ -88,7 +97,7 @@ /* Similar to Size(), but computes the expected size of a structure based \ * on the process’ bitness. This can be used prior to reading any data \ * from a process. */ \ - static size_t ExpectedSize(ProcessReader* process_reader); \ + static size_t ExpectedSize(ProcessReader* process_reader); #define PROCESS_TYPE_STRUCT_MEMBER(member_type, member_name, ...) \ member_type member_name __VA_ARGS__; @@ -155,6 +164,7 @@ using UIntPtr = typename Traits::UIntPtr; \ using Reserved32_64Only = typename Traits::Reserved32_64Only; \ using Reserved64_64Only = typename Traits::Reserved64_64Only; \ + using Nothing = typename Traits::Nothing; \ \ /* Read(), ReadArrayInto(), and Size() are as in the generic user-visible \ * struct above. */ \
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_types/custom.cc b/third_party/crashpad/crashpad/snapshot/mac/process_types/custom.cc index 5fe9228..33e3a7ec 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/process_types/custom.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/process_types/custom.cc
@@ -17,6 +17,8 @@ #include <string.h> #include <sys/types.h> +#include <type_traits> + #include "base/logging.h" #include "snapshot/mac/process_types/internal.h" #include "util/mach/task_memory.h" @@ -62,46 +64,31 @@ template <typename Traits> size_t dyld_all_image_infos<Traits>::ExpectedSizeForVersion( decltype(dyld_all_image_infos<Traits>::version) version) { - if (version >= 14) { - return sizeof(dyld_all_image_infos<Traits>); + const size_t kSizeForVersion[] = { + offsetof(dyld_all_image_infos<Traits>, infoArrayCount), // 0 + offsetof(dyld_all_image_infos<Traits>, libSystemInitialized), // 1 + offsetof(dyld_all_image_infos<Traits>, jitInfo), // 2 + offsetof(dyld_all_image_infos<Traits>, dyldVersion), // 3 + offsetof(dyld_all_image_infos<Traits>, dyldVersion), // 4 + offsetof(dyld_all_image_infos<Traits>, coreSymbolicationShmPage), // 5 + offsetof(dyld_all_image_infos<Traits>, systemOrderFlag), // 6 + offsetof(dyld_all_image_infos<Traits>, uuidArrayCount), // 7 + offsetof(dyld_all_image_infos<Traits>, dyldAllImageInfosAddress), // 8 + offsetof(dyld_all_image_infos<Traits>, initialImageCount), // 9 + offsetof(dyld_all_image_infos<Traits>, errorKind), // 10 + offsetof(dyld_all_image_infos<Traits>, sharedCacheSlide), // 11 + offsetof(dyld_all_image_infos<Traits>, sharedCacheUUID), // 12 + offsetof(dyld_all_image_infos<Traits>, infoArrayChangeTimestamp), // 13 + offsetof(dyld_all_image_infos<Traits>, end), // 14 + }; + + if (version >= arraysize(kSizeForVersion)) { + return kSizeForVersion[arraysize(kSizeForVersion) - 1]; } - if (version >= 13) { - return offsetof(dyld_all_image_infos<Traits>, infoArrayChangeTimestamp); - } - if (version >= 12) { - return offsetof(dyld_all_image_infos<Traits>, sharedCacheUUID); - } - if (version >= 11) { - return offsetof(dyld_all_image_infos<Traits>, sharedCacheSlide); - } - if (version >= 10) { - return offsetof(dyld_all_image_infos<Traits>, errorKind); - } - if (version >= 9) { - return offsetof(dyld_all_image_infos<Traits>, initialImageCount); - } - if (version >= 8) { - return offsetof(dyld_all_image_infos<Traits>, dyldAllImageInfosAddress); - } - if (version >= 7) { - return offsetof(dyld_all_image_infos<Traits>, uuidArrayCount); - } - if (version >= 6) { - return offsetof(dyld_all_image_infos<Traits>, systemOrderFlag); - } - if (version >= 5) { - return offsetof(dyld_all_image_infos<Traits>, coreSymbolicationShmPage); - } - if (version >= 3) { - return offsetof(dyld_all_image_infos<Traits>, dyldVersion); - } - if (version >= 2) { - return offsetof(dyld_all_image_infos<Traits>, jitInfo); - } - if (version >= 1) { - return offsetof(dyld_all_image_infos<Traits>, libSystemInitialized); - } - return offsetof(dyld_all_image_infos<Traits>, infoArrayCount); + + static_assert(std::is_unsigned<decltype(version)>::value, + "version must be unsigned"); + return kSizeForVersion[version]; } // static
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_types/dyld_images.proctype b/third_party/crashpad/crashpad/snapshot/mac/process_types/dyld_images.proctype index eb8410a..3470ee8 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/process_types/dyld_images.proctype +++ b/third_party/crashpad/crashpad/snapshot/mac/process_types/dyld_images.proctype
@@ -123,6 +123,13 @@ PROCESS_TYPE_STRUCT_MEMBER(Reserved64_64Only, reserved_6) PROCESS_TYPE_STRUCT_MEMBER(Reserved64_64Only, reserved_7) PROCESS_TYPE_STRUCT_MEMBER(Reserved64_64Only, reserved_8) + + // The 32-bit version of the structure will have four extra bytes of tail + // padding when built for 64-bit systems than it does natively and when built + // for 32-bit systems. Instead of using sizeof(dyld_all_image_infos), use + // offsetof(dyld_all_image_infos, end) to avoid taking this tail padding into + // account. + PROCESS_TYPE_STRUCT_MEMBER(Nothing, end) PROCESS_TYPE_STRUCT_END(dyld_all_image_infos) #endif // ! PROCESS_TYPE_STRUCT_IMPLEMENT_INTERNAL_READ_INTO &&
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_types/traits.h b/third_party/crashpad/crashpad/snapshot/mac/process_types/traits.h index fec234d..396799be 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/process_types/traits.h +++ b/third_party/crashpad/crashpad/snapshot/mac/process_types/traits.h
@@ -22,7 +22,8 @@ // DECLARE_PROCESS_TYPE_TRAITS_CLASS before #including this file again and after // the last #include of this file. // -// |Reserved*| are used for padding fields that may be zero-length, and thus +// |Reserved*| is used for padding fields that may be zero-length, and |Nothing| +// is always zero-length and is used solely as an anchor to compute offsets. // __VA_ARGS__, which is intended to set the alignment of the 64-bit types, is // not used for those type aliases. #define DECLARE_PROCESS_TYPE_TRAITS_CLASS(traits_name, lp_bits, ...) \ @@ -37,6 +38,7 @@ using UIntPtr = uint##lp_bits##_t __VA_ARGS__; \ using Reserved32_64Only = Reserved32_64Only##lp_bits; \ using Reserved64_64Only = Reserved64_64Only##lp_bits; \ + using Nothing = Nothing; \ }; \ } \ } \
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_types_test.cc b/third_party/crashpad/crashpad/snapshot/mac/process_types_test.cc index ce092fe..8525c14 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/process_types_test.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/process_types_test.cc
@@ -24,6 +24,7 @@ #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gtest/gtest.h" +#include "snapshot/mac/process_types/internal.h" #include "test/mac/dyld.h" #include "util/mac/mac_util.h" #include "util/misc/implicit_cast.h" @@ -116,6 +117,42 @@ process_types::dyld_all_image_infos::ExpectedSizeForVersion( &process_reader, kDyldAllImageInfosVersionInSDK)); + // Make sure that the computed sizes of various versions of this structure are + // correct at different bitnessses. + const struct { + uint32_t version; + size_t size_32; + size_t size_64; + } kVersionsAndSizes[] = { + {1, 17, 25}, + {2, 24, 40}, + {3, 28, 48}, + {5, 40, 72}, + {6, 44, 80}, + {7, 48, 88}, + {8, 56, 104}, + {9, 60, 112}, + {10, 64, 120}, + {11, 80, 152}, + {12, 84, 160}, + {13, 104, 184}, + {14, 164, 304}, + {15, 164, 304}, + }; + for (size_t index = 0; index < arraysize(kVersionsAndSizes); ++index) { + uint32_t version = kVersionsAndSizes[index].version; + SCOPED_TRACE(base::StringPrintf("index %zu, version %u", index, version)); + + EXPECT_EQ(kVersionsAndSizes[index].size_32, + process_types::internal::dyld_all_image_infos< + process_types::internal::Traits32>:: + ExpectedSizeForVersion(version)); + EXPECT_EQ(kVersionsAndSizes[index].size_64, + process_types::internal::dyld_all_image_infos< + process_types::internal::Traits64>:: + ExpectedSizeForVersion(version)); + } + process_types::dyld_all_image_infos proctype_image_infos; ASSERT_TRUE(proctype_image_infos.Read(&process_reader, dyld_info.all_image_info_addr));
diff --git a/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac.cc b/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac.cc index 3c39088f..b65a9e08 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac.cc
@@ -19,6 +19,8 @@ #include <sys/utsname.h> #include <time.h> +#include <algorithm> + #include "base/logging.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" @@ -349,34 +351,44 @@ PCHECK(localtime_r(&snapshot_time_->tv_sec, &local)) << "localtime_r"; *standard_name = tzname[0]; + + bool found_transition = false; + long probe_gmtoff = local.tm_gmtoff; if (daylight) { // Scan forward and backward, one month at a time, looking for an instance // when the observance of daylight saving time is different than it is in - // |local|. - long probe_gmtoff = local.tm_gmtoff; - + // |local|. It’s possible that no such instance will be found even with + // |daylight| set. This can happen in locations where daylight saving time + // was once observed or is expected to be observed in the future, but where + // no transitions to or from daylight saving time occurred or will occur + // within a year of the current date. Arizona, which last observed daylight + // saving time in 1967, is an example. const int kMonthDeltas[] = { 0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, 8, -8, 9, -9, 10, -10, 11, -11, 12, -12 }; - for (size_t index = 0; index < arraysize(kMonthDeltas); ++index) { - // Look at the 15th day of each month at local noon. Set tm_isdst to -1 to - // avoid giving mktime() any hints about whether to consider daylight - // saving time in effect. mktime() accepts values of tm_mon that are - // outside of its normal range and behaves as expected: if tm_mon is -1, - // it references December of the preceding year, and if it is 12, it + for (size_t index = 0; + index < arraysize(kMonthDeltas) && !found_transition; + ++index) { + // Look at a day of each month at local noon. Set tm_isdst to -1 to avoid + // giving mktime() any hints about whether to consider daylight saving + // time in effect. mktime() accepts values of tm_mon that are outside of + // its normal range and behaves as expected: if tm_mon is -1, it + // references December of the preceding year, and if it is 12, it // references January of the following year. tm probe_tm = {}; probe_tm.tm_hour = 12; - probe_tm.tm_mday = 15; + probe_tm.tm_mday = std::min(local.tm_mday, 28); probe_tm.tm_mon = local.tm_mon + kMonthDeltas[index]; probe_tm.tm_year = local.tm_year; probe_tm.tm_isdst = -1; if (mktime(&probe_tm) != -1 && probe_tm.tm_isdst != local.tm_isdst) { + found_transition = true; probe_gmtoff = probe_tm.tm_gmtoff; - break; } } + } + if (found_transition) { *daylight_name = tzname[1]; if (!local.tm_isdst) { *dst_status = kObservingStandardTime;
diff --git a/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac_test.cc b/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac_test.cc index a02e94e0..aff773f 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac_test.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac_test.cc
@@ -14,11 +14,13 @@ #include "snapshot/mac/system_snapshot_mac.h" +#include <stdlib.h> #include <sys/time.h> #include <time.h> #include <string> +#include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gtest/gtest.h" #include "snapshot/mac/process_reader.h" @@ -127,6 +129,39 @@ EXPECT_FALSE(system_snapshot().MachineDescription().empty()); } +class ScopedSetTZ { + public: + ScopedSetTZ(const std::string& tz) { + const char* old_tz = getenv(kTZ); + old_tz_set_ = old_tz; + if (old_tz_set_) { + old_tz_.assign(old_tz); + } + + EXPECT_EQ(0, setenv(kTZ, tz.c_str(), 1)) << ErrnoMessage("setenv"); + tzset(); + } + + ~ScopedSetTZ() { + if (old_tz_set_) { + EXPECT_EQ(0, setenv(kTZ, old_tz_.c_str(), 1)) << ErrnoMessage("setenv"); + } else { + EXPECT_EQ(0, unsetenv(kTZ)) << ErrnoMessage("unsetenv"); + } + tzset(); + } + + private: + std::string old_tz_; + bool old_tz_set_; + + static constexpr char kTZ[] = "TZ"; + + DISALLOW_COPY_AND_ASSIGN(ScopedSetTZ); +}; + +constexpr char ScopedSetTZ::kTZ[]; + TEST_F(SystemSnapshotMacTest, TimeZone) { SystemSnapshot::DaylightSavingTimeStatus dst_status; int standard_offset_seconds; @@ -169,6 +204,68 @@ EXPECT_NE(standard_name, daylight_name); } + + // Test a variety of time zones. Some of these observe daylight saving time, + // some don’t. Some used to but no longer do. Some have uncommon UTC offsets. + const struct { + const char* tz; + bool observes_dst; + float standard_offset_hours; + float daylight_offset_hours; + const char* standard_name; + const char* daylight_name; + } kTestTimeZones[] = { + {"America/Anchorage", true, -9, -8, "AKST", "AKDT"}, + {"America/Chicago", true, -6, -5, "CST", "CDT"}, + {"America/Denver", true, -7, -6, "MST", "MDT"}, + {"America/Halifax", true, -4, -3, "AST", "ADT"}, + {"America/Los_Angeles", true, -8, -7, "PST", "PDT"}, + {"America/New_York", true, -5, -4, "EST", "EDT"}, + {"America/Phoenix", false, -7, -7, "MST", "MST"}, + {"Asia/Karachi", false, 5, 5, "PKT", "PKT"}, + {"Asia/Kolkata", false, 5.5, 5.5, "IST", "IST"}, + {"Asia/Shanghai", false, 8, 8, "CST", "CST"}, + {"Asia/Tokyo", false, 9, 9, "JST", "JST"}, + {"Australia/Adelaide", true, 9.5, 10.5, "ACST", "ACDT"}, + {"Australia/Brisbane", false, 10, 10, "AEST", "AEST"}, + {"Australia/Darwin", false, 9.5, 9.5, "ACST", "ACST"}, + {"Australia/Eucla", false, 8.75, 8.75, "ACWST", "ACWST"}, + {"Australia/Lord_Howe", true, 10.5, 11, "LHST", "LHDT"}, + {"Australia/Perth", false, 8, 8, "AWST", "AWST"}, + {"Australia/Sydney", true, 10, 11, "AEST", "AEDT"}, + {"Europe/Bucharest", true, 2, 3, "EET", "EEST"}, + {"Europe/London", true, 0, 1, "GMT", "BST"}, + {"Europe/Moscow", false, 3, 3, "MSK", "MSK"}, + {"Europe/Paris", true, 1, 2, "CET", "CEST"}, + {"Europe/Reykjavik", false, 0, 0, "UTC", "UTC"}, + {"Pacific/Auckland", true, 12, 13, "NZST", "NZDT"}, + {"Pacific/Honolulu", false, -10, -10, "HST", "HST"}, + {"UTC", false, 0, 0, "UTC", "UTC"}, + }; + + for (size_t index = 0; index < arraysize(kTestTimeZones); ++index) { + const auto& test_time_zone = kTestTimeZones[index]; + const char* tz = test_time_zone.tz; + SCOPED_TRACE(base::StringPrintf("index %zu, tz %s", index, tz)); + + { + ScopedSetTZ set_tz(tz); + system_snapshot().TimeZone(&dst_status, + &standard_offset_seconds, + &daylight_offset_seconds, + &standard_name, + &daylight_name); + } + + EXPECT_EQ(test_time_zone.observes_dst, + dst_status != SystemSnapshot::kDoesNotObserveDaylightSavingTime); + EXPECT_EQ(test_time_zone.standard_offset_hours * 60 * 60, + standard_offset_seconds); + EXPECT_EQ(test_time_zone.daylight_offset_hours * 60 * 60, + daylight_offset_seconds); + EXPECT_EQ(test_time_zone.standard_name, standard_name); + EXPECT_EQ(test_time_zone.daylight_name, daylight_name); + } } } // namespace
diff --git a/third_party/crashpad/crashpad/util/mach/exception_types.cc b/third_party/crashpad/crashpad/util/mach/exception_types.cc index d33fa937..e133cb9ad 100644 --- a/third_party/crashpad/crashpad/util/mach/exception_types.cc +++ b/third_party/crashpad/crashpad/util/mach/exception_types.cc
@@ -309,15 +309,32 @@ if (resource_type == RESOURCE_TYPE_MEMORY && resource_flavor == FLAVOR_HIGH_WATERMARK) { - // These exceptions are never fatal. See 10.10 + // These exceptions were never fatal prior to 10.12. See 10.10 // xnu-2782.1.97/osfmk/kern/task.c // THIS_PROCESS_CROSSED_HIGH_WATERMARK__SENDING_EXC_RESOURCE(). + // + // A superficial examination of 10.12 shows that these exceptions may be + // fatal, as determined by the P_MEMSTAT_FATAL_MEMLIMIT bit of the + // kernel-internal struct proc::p_memstat_state. See 10.12.3 + // xnu-3789.41.3/osfmk/kern/task.c task_footprint_exceeded(). This bit is + // not exposed to user space, which makes it difficult to determine whether + // the kernel considers a given instance of this exception fatal. However, a + // close read reveals that it is only possible for this bit to become set + // when xnu-3789.41.3/bsd/kern/kern_memorystatus.c + // memorystatus_cmd_set_memlimit_properties() is called, which is only + // possible when the kernel is built with CONFIG_JETSAM set, or if the + // kern.memorystatus_highwater_enabled sysctl is used, which is only + // possible when the kernel is built with DEVELOPMENT or DEBUG set. Although + // CONFIG_JETSAM is used on iOS, it is not used on macOS. DEVELOPMENT and + // DEBUG are also not set for production kernels. It therefore remains + // impossible for these exceptions to be fatal, even on 10.12. return true; } if (resource_type == RESOURCE_TYPE_IO) { - // These exceptions don’t ever appear to be fatal. See - // https://crashpad.chromium.org/bug/124. + // These exceptions are never fatal. See 10.12.3 + // xnu-3789.41.3/osfmk/kern/task.c + // SENDING_NOTIFICATION__THIS_PROCESS_IS_CAUSING_TOO_MUCH_IO(). return true; }
diff --git a/third_party/crashpad/crashpad/util/mach/exception_types_test.cc b/third_party/crashpad/crashpad/util/mach/exception_types_test.cc index 7ecdd25..4175c63 100644 --- a/third_party/crashpad/crashpad/util/mach/exception_types_test.cc +++ b/third_party/crashpad/crashpad/util/mach/exception_types_test.cc
@@ -57,7 +57,13 @@ {0x0700080, EXC_SYSCALL, 128, 0}, {0x0706000, EXC_SYSCALL, 0x6000, 0}, {0x3000000, 0, 0, SIGQUIT}, + {0x4000000, 0, 0, SIGILL}, + {0x5000000, 0, 0, SIGTRAP}, {0x6000000, 0, 0, SIGABRT}, + {0x7000000, 0, 0, SIGEMT}, + {0x8000000, 0, 0, SIGFPE}, + {0xa000000, 0, 0, SIGBUS}, + {0xb000000, 0, 0, SIGSEGV}, {0xc000000, 0, 0, SIGSYS}, {0, 0, 0, 0}, }; @@ -181,7 +187,13 @@ #define ENCODE_EXC_CRASH_SIGNAL(signal) \ { EXC_CRASH, (((signal) & 0xff) << 24), (EXC_CRASH << 16) | (signal) } ENCODE_EXC_CRASH_SIGNAL(SIGQUIT), + ENCODE_EXC_CRASH_SIGNAL(SIGILL), + ENCODE_EXC_CRASH_SIGNAL(SIGTRAP), ENCODE_EXC_CRASH_SIGNAL(SIGABRT), + ENCODE_EXC_CRASH_SIGNAL(SIGEMT), + ENCODE_EXC_CRASH_SIGNAL(SIGFPE), + ENCODE_EXC_CRASH_SIGNAL(SIGBUS), + ENCODE_EXC_CRASH_SIGNAL(SIGSEGV), ENCODE_EXC_CRASH_SIGNAL(SIGSYS), #undef ENCODE_EXC_CRASH_SIGNAL
diff --git a/third_party/crashpad/crashpad/util/thread/thread_log_messages.cc b/third_party/crashpad/crashpad/util/thread/thread_log_messages.cc index dec111e7..60be08b5 100644 --- a/third_party/crashpad/crashpad/util/thread/thread_log_messages.cc +++ b/third_party/crashpad/crashpad/util/thread/thread_log_messages.cc
@@ -16,7 +16,6 @@ #include <sys/types.h> -#include "base/lazy_instance.h" #include "base/logging.h" #include "base/threading/thread_local_storage.h" @@ -28,14 +27,24 @@ // handler. A thread may register its thread-specific log message list to // receive messages produced just on that thread. // -// Only one object of this class may exist in the program at a time. There must -// not be any log message handler in effect when it is created, and nothing else -// can be set as a log message handler while an object of this class exists. -// -// Practically, the only object of this class that might exist is managed by the -// g_master lazy instance, which will create it upon first use. +// Only one object of this class may exist in the program at a time as created +// by GetInstance(). There must not be any log message handler in effect when it +// is created, and nothing else can be set as a log message handler while an +// object of this class exists. class ThreadLogMessagesMaster { public: + void SetThreadMessageList(std::vector<std::string>* message_list) { + DCHECK_EQ(logging::GetLogMessageHandler(), &LogMessageHandler); + DCHECK_NE(tls_.Get() != nullptr, message_list != nullptr); + tls_.Set(message_list); + } + + static ThreadLogMessagesMaster* GetInstance() { + static auto master = new ThreadLogMessagesMaster(); + return master; + } + + private: ThreadLogMessagesMaster() { DCHECK(!tls_.initialized()); tls_.Initialize(nullptr); @@ -45,20 +54,8 @@ logging::SetLogMessageHandler(LogMessageHandler); } - ~ThreadLogMessagesMaster() { - DCHECK_EQ(logging::GetLogMessageHandler(), &LogMessageHandler); - logging::SetLogMessageHandler(nullptr); + ~ThreadLogMessagesMaster() = delete; - tls_.Free(); - } - - void SetThreadMessageList(std::vector<std::string>* message_list) { - DCHECK_EQ(logging::GetLogMessageHandler(), &LogMessageHandler); - DCHECK_NE(tls_.Get() != nullptr, message_list != nullptr); - tls_.Set(message_list); - } - - private: static bool LogMessageHandler(logging::LogSeverity severity, const char* file_path, int line, @@ -84,18 +81,14 @@ base::ThreadLocalStorage::StaticSlot ThreadLogMessagesMaster::tls_ = TLS_INITIALIZER; -base::LazyInstance<ThreadLogMessagesMaster>::Leaky g_master = - LAZY_INSTANCE_INITIALIZER; - } // namespace -ThreadLogMessages::ThreadLogMessages() - : log_messages_() { - g_master.Get().SetThreadMessageList(&log_messages_); +ThreadLogMessages::ThreadLogMessages() : log_messages_() { + ThreadLogMessagesMaster::GetInstance()->SetThreadMessageList(&log_messages_); } ThreadLogMessages::~ThreadLogMessages() { - g_master.Get().SetThreadMessageList(nullptr); + ThreadLogMessagesMaster::GetInstance()->SetThreadMessageList(nullptr); } } // namespace crashpad
diff --git a/third_party/gvr-android-sdk/OWNERS b/third_party/gvr-android-sdk/OWNERS index 2b169ac..c18048da 100644 --- a/third_party/gvr-android-sdk/OWNERS +++ b/third_party/gvr-android-sdk/OWNERS
@@ -1,2 +1,4 @@ bajones@chromium.org bshe@chromium.org + +# COMPONENT: UI>Browser>VR
diff --git a/tools/android/eclipse/.classpath b/tools/android/eclipse/.classpath index 41bb456..f4f1b5e 100644 --- a/tools/android/eclipse/.classpath +++ b/tools/android/eclipse/.classpath
@@ -225,6 +225,7 @@ <classpathentry kind="lib" path="third_party/bouncycastle/lib/bcprov-jdk16-1.46.jar"/> <classpathentry kind="lib" path="third_party/byte_buddy/lib/byte-buddy-1.4.17.jar"/> <classpathentry kind="lib" path="third_party/findbugs/lib/findbugs.jar"/> + <classpathentry kind="lib" path="third_party/hamcrest/lib/hamcrest-library-1.3.jar"/> <classpathentry kind="lib" path="third_party/intellij/lib/annotations-12.0.jar"/> <classpathentry kind="lib" path="third_party/junit/src/lib/hamcrest-core-1.3.jar" sourcepath="third_party/junit/src/lib/hamcrest-core-1.3-sources.jar"/> <classpathentry kind="lib" path="third_party/objenesis/lib/objenesis-2.4.jar"/>
diff --git a/tools/checkteamtags/extract_components.py b/tools/checkteamtags/extract_components.py index a96fa039..e944894 100755 --- a/tools/checkteamtags/extract_components.py +++ b/tools/checkteamtags/extract_components.py
@@ -44,6 +44,86 @@ f.write(data) +def display_stat(stats, root, options): + """"Display coverage statistic. + + The following three values are always displayed: + - The total number of OWNERS files under directory root and its sub- + directories. + - The number of OWNERS files (and its percentage of the total) that have + component information but no team information. + - The number of OWNERS files (and its percentage of the total) that have + both component and team information. + + Optionally, if options.stat_coverage or options.complete_coverage are given, + the same information will be shown for each depth level. + (up to the level given by options.stat_coverage, if any). + + Args: + stats (dict): Tha statistics in dictionary form as produced by the + owners_file_tags module. + root (str): The root directory from which the depth level is calculated. + options (optparse.Values): The command line options as returned by + optparse. + """ + file_total = stats['OWNERS-count'] + print ("%d OWNERS files in total." % file_total) + file_with_component = stats['OWNERS-with-component-only-count'] + file_pct_with_component = "N/A" + if file_total > 0: + file_pct_with_component = "{0:.2f}".format( + 100.0 * file_with_component / file_total) + print '%(file_with_component)d (%(file_pct_with_component)s%%) OWNERS '\ + 'files have COMPONENT' % { + 'file_with_component': file_with_component, + 'file_pct_with_component': file_pct_with_component} + file_with_team_component = stats['OWNERS-with-team-and-component-count'] + file_pct_with_team_component = "N/A" + if file_total > 0: + file_pct_with_team_component = "{0:.2f}".format( + 100.0 * file_with_team_component / file_total) + print '%(file_with_team_component)d (%(file_pct_with_team_component)s%%) '\ + 'OWNERS files have TEAM and COMPONENT' % { + 'file_with_team_component': file_with_team_component, + 'file_pct_with_team_component': file_pct_with_team_component} + + print ("\nUnder directory %s " % root) + # number of depth to display, default is max depth under root + num_output_depth = len(stats['OWNERS-count-by-depth']) + if (options.stat_coverage > 0 + and options.stat_coverage < num_output_depth): + num_output_depth = options.stat_coverage + + for depth in range(0, num_output_depth): + file_total_by_depth = stats['OWNERS-count-by-depth'][depth] + file_with_component_by_depth =\ + stats['OWNERS-with-component-only-count-by-depth'][depth] + file_pct_with_component_by_depth = "N/A" + if file_total_by_depth > 0: + file_pct_with_component_by_depth = "{0:.2f}".format( + 100.0 * file_with_component_by_depth / file_total_by_depth) + file_with_team_component_by_depth =\ + stats['OWNERS-with-team-and-component-count-by-depth'][depth] + file_pct_with_team_component_by_depth = "N/A" + if file_total_by_depth > 0: + file_pct_with_team_component_by_depth = "{0:.2f}".format( + 100.0 * file_with_team_component_by_depth / file_total_by_depth) + print '%(file_total_by_depth)d OWNERS files at depth %(depth)d'% { + 'file_total_by_depth': file_total_by_depth, 'depth': depth} + print 'have COMPONENT: %(file_with_component_by_depth)d, '\ + 'percentage: %(file_pct_with_component_by_depth)s%%' % { + 'file_with_component_by_depth': + file_with_component_by_depth, + 'file_pct_with_component_by_depth': + file_pct_with_component_by_depth} + print 'have COMPONENT and TEAM: %(file_with_team_component_by_depth)d,'\ + 'percentage: %(file_pct_with_team_component_by_depth)s%%' % { + 'file_with_team_component_by_depth': + file_with_team_component_by_depth, + 'file_pct_with_team_component_by_depth': + file_pct_with_team_component_by_depth} + + def main(argv): usage = """Usage: python %prog [options] [<root_dir>] root_dir specifies the topmost directory to traverse looking for OWNERS @@ -56,6 +136,8 @@ python %prog -v /b/build/src python %prog -w /b/build/src python %prog -o ~/components.json /b/build/src + python %prog -c /b/build/src + python %prog -s 3 /b/build/src """ parser = optparse.OptionParser(usage=usage) parser.add_option('-w', '--write', action='store_true', @@ -67,13 +149,17 @@ parser.add_option('-o', '--output_file', help='Specify file to write the ' 'mappings to instead of the default: <CWD>/' 'component_map.json (implies -w)') + parser.add_option('-c', '--complete_coverage', action='store_true', + help='Print complete coverage statistic') + parser.add_option('-s', '--stat_coverage', type="int", + help='Specify directory depth to display coverage stats') options, args = parser.parse_args(argv[1:]) if args: root = args[0] else: root = _DEFAULT_SRC_LOCATION - mappings, warnings, errors = aggregate_components_from_owners(root) + mappings, warnings, errors, stats = aggregate_components_from_owners(root) if options.verbose: for w in warnings: print w @@ -81,6 +167,9 @@ for e in errors: print e + if options.stat_coverage or options.complete_coverage: + display_stat(stats, root, options) + mappings['AAA-README']= _README mapping_file_contents = json.dumps(mappings, sort_keys=True, indent=2) if options.write or options.output_file:
diff --git a/tools/checkteamtags/extract_components_test.py b/tools/checkteamtags/extract_components_test.py index b9111659..0f99f4e 100644 --- a/tools/checkteamtags/extract_components_test.py +++ b/tools/checkteamtags/extract_components_test.py
@@ -124,3 +124,41 @@ output = saved_output.getvalue() self.assertIn('src/OWNERS has no COMPONENT tag', output) + @mock_file_tree({ + 'src': 'boss@chromium.org\n', + 'src/dummydir1': 'dummy@chromium.org\n' + '# TEAM: dummy-team@chromium.org\n' + '# COMPONENT: Dummy>Component', + 'src/dummydir2': 'dummy2@chromium.org\n' + '# COMPONENT: Dummy>Component', + 'src/dummydir1/innerdir1': 'dummy@chromium.org\n' + '# TEAM: dummy-specialist-team@chromium.org\n' + '# COMPONENT: Dummy>Component>Subcomponent'}) + def testCoverage(self): + saved_output = StringIO() + with mock.patch('sys.stdout', saved_output): + extract_components.main(['%prog', '-s 2']) + output = saved_output.getvalue() + self.assertIn('4 OWNERS files in total.', output) + self.assertIn('3 (75.00%) OWNERS files have COMPONENT', output) + self.assertIn('2 (50.00%) OWNERS files have TEAM and COMPONENT', output) + + @mock_file_tree({ + 'src': 'boss@chromium.org\n', + 'src/dummydir1': 'dummy@chromium.org\n' + '# TEAM: dummy-team@chromium.org\n' + '# COMPONENT: Dummy>Component', + 'src/dummydir2': 'dummy2@chromium.org\n' + '# COMPONENT: Dummy>Component', + 'src/dummydir1/innerdir1': 'dummy@chromium.org\n' + '# TEAM: dummy-specialist-team@chromium.org\n' + '# COMPONENT: Dummy>Component>Subcomponent'}) + def testCompleteCoverage(self): + saved_output = StringIO() + with mock.patch('sys.stdout', saved_output): + extract_components.main(['%prog', '-c']) + output = saved_output.getvalue() + self.assertIn('4 OWNERS files in total.', output) + self.assertIn('3 (75.00%) OWNERS files have COMPONENT', output) + self.assertIn('2 (50.00%) OWNERS files have TEAM and COMPONENT', output) + self.assertIn('4 OWNERS files at depth 0', output)
diff --git a/tools/checkteamtags/owners_file_tags.py b/tools/checkteamtags/owners_file_tags.py index fc8d1f5..d2e3fe9 100644 --- a/tools/checkteamtags/owners_file_tags.py +++ b/tools/checkteamtags/owners_file_tags.py
@@ -39,11 +39,26 @@ root (str): the path to the src directory. Returns: - A pair (data, warnings) where data is a dict of the form + A tuple (data, warnings, errors, stats) where data is a dict of the form {'component-to-team': {'Component1': 'team1@chr...', ...}, 'dir-to-component': {'/path/to/1': 'Component1', ...}} - and warnings is a list of strings. + , warnings is a list of strings, stats is a dict of form + {'OWNERS-count': total number of OWNERS files, + 'OWNERS-with-component-only-count': number of OWNERS have # COMPONENT, + 'OWNERS-with-team-and-component-count': number of + OWNERS have TEAM and COMPONENT, + 'OWNERS-count-by-depth': {directory depth: number of OWNERS}, + 'OWNERS-with-component-only-count-by-depth': {directory depth: number + of OWNERS have COMPONENT at this depth}, + 'OWNERS-with-team-and-component-count-by-depth':{directory depth: ...}} """ + stats = {} + num_total = 0 + num_with_component = 0 + num_with_team_component = 0 + num_total_by_depth = defaultdict(int) + num_with_component_by_depth = defaultdict(int) + num_with_team_component_by_depth = defaultdict(int) warnings = [] component_to_team = defaultdict(set) dir_to_component = {} @@ -51,19 +66,34 @@ # Proofing against windows casing oddities. owners_file_names = [f for f in files if f.upper() == 'OWNERS'] if owners_file_names: + file_depth = dirname[len(root) + len(os.path.sep):].count(os.path.sep) + num_total += 1 + num_total_by_depth[file_depth] += 1 owners_full_path = os.path.join(dirname, owners_file_names[0]) owners_rel_path = os.path.relpath(owners_full_path, root) team, component = parse(owners_full_path) if component: + num_with_component += 1 + num_with_component_by_depth[file_depth] += 1 dir_to_component[os.path.relpath(dirname, root)] = component if team: + num_with_team_component += 1 + num_with_team_component_by_depth[file_depth] += 1 component_to_team[component].add(team) else: warnings.append('%s has no COMPONENT tag' % owners_rel_path) mappings = {'component-to-team': component_to_team, 'dir-to-component': dir_to_component} errors = validate_one_team_per_component(mappings) - return unwrap(mappings), warnings, errors + stats = {'OWNERS-count': num_total, + 'OWNERS-with-component-only-count': num_with_component, + 'OWNERS-with-team-and-component-count': num_with_team_component, + 'OWNERS-count-by-depth': num_total_by_depth, + 'OWNERS-with-component-only-count-by-depth': + num_with_component_by_depth, + 'OWNERS-with-team-and-component-count-by-depth': + num_with_team_component_by_depth} + return unwrap(mappings), warnings, errors, stats def validate_one_team_per_component(m):
diff --git a/tools/clang/blink_gc_plugin/DiagnosticsReporter.cpp b/tools/clang/blink_gc_plugin/DiagnosticsReporter.cpp index 1ae84257..a43cfdb0d 100644 --- a/tools/clang/blink_gc_plugin/DiagnosticsReporter.cpp +++ b/tools/clang/blink_gc_plugin/DiagnosticsReporter.cpp
@@ -210,6 +210,8 @@ getErrorLevel(), kLeftMostBaseMustBePolymorphic); diag_base_class_must_declare_virtual_trace_ = diagnostic_.getCustomDiagID( getErrorLevel(), kBaseClassMustDeclareVirtualTrace); + diag_iterator_to_gc_managed_collection_note_ = diagnostic_.getCustomDiagID( + getErrorLevel(), kIteratorToGCManagedCollectionNote); // Register note messages. diag_base_requires_tracing_note_ = diagnostic_.getCustomDiagID( @@ -256,8 +258,6 @@ DiagnosticsEngine::Note, kOverriddenNonVirtualTraceNote); diag_manual_dispatch_method_note_ = diagnostic_.getCustomDiagID( DiagnosticsEngine::Note, kManualDispatchMethodNote); - diag_iterator_to_gc_managed_collection_note_ = diagnostic_.getCustomDiagID( - DiagnosticsEngine::Note, kIteratorToGCManagedCollectionNote); } bool DiagnosticsReporter::hasErrorOccurred() const
diff --git a/tools/clang/blink_gc_plugin/tests/fields_illegal_tracing.txt b/tools/clang/blink_gc_plugin/tests/fields_illegal_tracing.txt index 5486505..dc7030b 100644 --- a/tools/clang/blink_gc_plugin/tests/fields_illegal_tracing.txt +++ b/tools/clang/blink_gc_plugin/tests/fields_illegal_tracing.txt
@@ -11,10 +11,10 @@ ./fields_illegal_tracing.h:40:5: note: [blink-gc] std::unique_ptr field 'm_obj4' to a GC managed class declared here: std::unique_ptr<HeapObject> m_obj4; ^ -./fields_illegal_tracing.h:42:5: note: [blink-gc] Iterator field 'm_iterator2' to a GC managed collection declared here: +./fields_illegal_tracing.h:42:5: warning: [blink-gc] Iterator field 'm_iterator2' to a GC managed collection declared here: HeapVector<Member<HeapObject>>::iterator m_iterator2; ^ -./fields_illegal_tracing.h:43:5: note: [blink-gc] Iterator field 'm_iterator3' to a GC managed collection declared here: +./fields_illegal_tracing.h:43:5: warning: [blink-gc] Iterator field 'm_iterator3' to a GC managed collection declared here: HeapHashSet<PartObject>::const_iterator m_iterator3; ^ ./fields_illegal_tracing.h:46:1: warning: [blink-gc] Class 'HeapObject' contains invalid fields. @@ -29,13 +29,13 @@ ./fields_illegal_tracing.h:54:5: note: [blink-gc] std::unique_ptr field 'm_obj4' to a GC managed class declared here: std::unique_ptr<HeapObject> m_obj4; ^ -./fields_illegal_tracing.h:55:5: note: [blink-gc] Iterator field 'm_iterator3' to a GC managed collection declared here: +./fields_illegal_tracing.h:55:5: warning: [blink-gc] Iterator field 'm_iterator3' to a GC managed collection declared here: HeapHashMap<int, Member<HeapObject>>::reverse_iterator m_iterator3; ^ -./fields_illegal_tracing.h:56:5: note: [blink-gc] Iterator field 'm_iterator4' to a GC managed collection declared here: +./fields_illegal_tracing.h:56:5: warning: [blink-gc] Iterator field 'm_iterator4' to a GC managed collection declared here: HeapDeque<Member<HeapObject>>::const_reverse_iterator m_iterator4; ^ -./fields_illegal_tracing.h:58:5: note: [blink-gc] Iterator field 'm_iterator6' to a GC managed collection declared here: +./fields_illegal_tracing.h:58:5: warning: [blink-gc] Iterator field 'm_iterator6' to a GC managed collection declared here: HeapLinkedHashSet<Member<HeapObject>>::const_iterator m_iterator6; ^ fields_illegal_tracing.cpp:9:1: warning: [blink-gc] Class 'PartObject' has untraced or not traceable fields. @@ -65,4 +65,4 @@ ./fields_illegal_tracing.h:57:5: note: [blink-gc] Untraced field 'm_iterator5' declared here: HeapListHashSet<Member<HeapObject>>::const_iterator m_iterator5; ^ -4 warnings generated. +9 warnings generated.
diff --git a/tools/clang/blink_gc_plugin/tests/legacy_naming/fields_illegal_tracing.txt b/tools/clang/blink_gc_plugin/tests/legacy_naming/fields_illegal_tracing.txt index 61dc6a2..874be1c 100644 --- a/tools/clang/blink_gc_plugin/tests/legacy_naming/fields_illegal_tracing.txt +++ b/tools/clang/blink_gc_plugin/tests/legacy_naming/fields_illegal_tracing.txt
@@ -11,10 +11,10 @@ ./fields_illegal_tracing.h:40:5: note: [blink-gc] std::unique_ptr field 'm_obj4' to a GC managed class declared here: std::unique_ptr<HeapObject> m_obj4; ^ -./fields_illegal_tracing.h:42:5: note: [blink-gc] Iterator field 'm_iterator2' to a GC managed collection declared here: +./fields_illegal_tracing.h:42:5: warning: [blink-gc] Iterator field 'm_iterator2' to a GC managed collection declared here: HeapVector<Member<HeapObject>>::iterator m_iterator2; ^ -./fields_illegal_tracing.h:43:5: note: [blink-gc] Iterator field 'm_iterator3' to a GC managed collection declared here: +./fields_illegal_tracing.h:43:5: warning: [blink-gc] Iterator field 'm_iterator3' to a GC managed collection declared here: HeapHashSet<PartObject>::const_iterator m_iterator3; ^ ./fields_illegal_tracing.h:46:1: warning: [blink-gc] Class 'HeapObject' contains invalid fields. @@ -29,13 +29,13 @@ ./fields_illegal_tracing.h:54:5: note: [blink-gc] std::unique_ptr field 'm_obj4' to a GC managed class declared here: std::unique_ptr<HeapObject> m_obj4; ^ -./fields_illegal_tracing.h:55:5: note: [blink-gc] Iterator field 'm_iterator3' to a GC managed collection declared here: +./fields_illegal_tracing.h:55:5: warning: [blink-gc] Iterator field 'm_iterator3' to a GC managed collection declared here: HeapHashMap<int, Member<HeapObject>>::reverse_iterator m_iterator3; ^ -./fields_illegal_tracing.h:56:5: note: [blink-gc] Iterator field 'm_iterator4' to a GC managed collection declared here: +./fields_illegal_tracing.h:56:5: warning: [blink-gc] Iterator field 'm_iterator4' to a GC managed collection declared here: HeapDeque<Member<HeapObject>>::const_reverse_iterator m_iterator4; ^ -./fields_illegal_tracing.h:58:5: note: [blink-gc] Iterator field 'm_iterator6' to a GC managed collection declared here: +./fields_illegal_tracing.h:58:5: warning: [blink-gc] Iterator field 'm_iterator6' to a GC managed collection declared here: HeapLinkedHashSet<Member<HeapObject>>::const_iterator m_iterator6; ^ fields_illegal_tracing.cpp:9:1: warning: [blink-gc] Class 'PartObject' has untraced or not traceable fields. @@ -65,4 +65,4 @@ ./fields_illegal_tracing.h:57:5: note: [blink-gc] Untraced field 'm_iterator5' declared here: HeapListHashSet<Member<HeapObject>>::const_iterator m_iterator5; ^ -4 warnings generated. +9 warnings generated.
diff --git a/tools/clang/rewrite_to_chrome_style/EditTracker.cpp b/tools/clang/rewrite_to_chrome_style/EditTracker.cpp index cd8228e..600fb024 100644 --- a/tools/clang/rewrite_to_chrome_style/EditTracker.cpp +++ b/tools/clang/rewrite_to_chrome_style/EditTracker.cpp
@@ -9,6 +9,27 @@ #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" +namespace { + +const char* GetTag(RenameCategory category) { + switch (category) { + case RenameCategory::kEnumValue: + return "enum"; + case RenameCategory::kField: + return "var"; + case RenameCategory::kFunction: + return "func"; + case RenameCategory::kUnresolved: + return "unresolved"; + case RenameCategory::kVariable: + return "var"; + } +} + +} // namespace + +EditTracker::EditTracker(RenameCategory category) : category_(category) {} + void EditTracker::Add(const clang::SourceManager& source_manager, clang::SourceLocation location, llvm::StringRef original_text, @@ -30,8 +51,8 @@ result.first->getValue().filenames.try_emplace(filename); } -void EditTracker::SerializeTo(llvm::StringRef tag, - llvm::raw_ostream& output) const { +void EditTracker::SerializeTo(llvm::raw_ostream& output) const { + const char* tag = GetTag(category_); for (const auto& edit : tracked_edits_) { for (const auto& filename : edit.getValue().filenames) { output << filename.getKey() << ":" << tag << ":" << edit.getKey() << ":"
diff --git a/tools/clang/rewrite_to_chrome_style/EditTracker.h b/tools/clang/rewrite_to_chrome_style/EditTracker.h index ef5e301..0d8bf0c1 100644 --- a/tools/clang/rewrite_to_chrome_style/EditTracker.h +++ b/tools/clang/rewrite_to_chrome_style/EditTracker.h
@@ -22,11 +22,19 @@ llvm::StringSet<> filenames; }; +enum class RenameCategory { + kEnumValue, + kField, + kFunction, + kUnresolved, + kVariable, +}; + // Simple class that tracks the edits made by path. Used to dump the databaes // used by the Blink rebase helper. class EditTracker { public: - EditTracker() = default; + explicit EditTracker(RenameCategory category); void Add(const clang::SourceManager& source_manager, clang::SourceLocation location, @@ -36,7 +44,7 @@ // Serializes the tracked edits to |output|. Emits: // <filename>:<tag>:<original text>:<new text> // for each distinct filename for each tracked edit. - void SerializeTo(llvm::StringRef tag, llvm::raw_ostream& output) const; + void SerializeTo(llvm::raw_ostream& output) const; private: EditTracker(const EditTracker&) = delete; @@ -44,6 +52,8 @@ // The string key is the original text. llvm::StringMap<EditInfo> tracked_edits_; + + RenameCategory category_; }; #endif // #define TOOLS_CLANG_REWRITE_TO_CHROME_STYLE_EDIT_TRACKER_H_
diff --git a/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp b/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp index c0c2ad13..8fa8ec2 100644 --- a/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp +++ b/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
@@ -1039,8 +1039,9 @@ template <typename TargetNode> class RewriterBase : public MatchFinder::MatchCallback { public: - explicit RewriterBase(std::set<Replacement>* replacements) - : replacements_(replacements) {} + explicit RewriterBase(std::set<Replacement>* replacements, + RenameCategory category) + : replacements_(replacements), edit_tracker_(category) {} const TargetNode& GetTargetNode(const MatchFinder::MatchResult& result) { const TargetNode* target_node = result.Nodes.getNodeAs<TargetNode>( @@ -1126,20 +1127,51 @@ edit_tracker_.Add(*result.SourceManager, loc, old_name, new_name); } - const EditTracker& edit_tracker() const { return edit_tracker_; } + const EditTracker* edit_tracker() const { return &edit_tracker_; } private: std::set<Replacement>* const replacements_; EditTracker edit_tracker_; }; +template <typename DeclNode> +RenameCategory GetCategory(); +template <> +RenameCategory GetCategory<clang::FieldDecl>() { + return RenameCategory::kField; +} +template <> +RenameCategory GetCategory<clang::VarDecl>() { + return RenameCategory::kVariable; +} +template <> +RenameCategory GetCategory<clang::FunctionDecl>() { + return RenameCategory::kFunction; +} +template <> +RenameCategory GetCategory<clang::CXXMethodDecl>() { + return RenameCategory::kFunction; +} +template <> +RenameCategory GetCategory<clang::EnumConstantDecl>() { + return RenameCategory::kEnumValue; +} +template <> +RenameCategory GetCategory<clang::NamedDecl>() { + return RenameCategory::kUnresolved; +} +template <> +RenameCategory GetCategory<clang::UsingDecl>() { + return RenameCategory::kUnresolved; +} + template <typename DeclNode, typename TargetNode> class DeclRewriterBase : public RewriterBase<TargetNode> { public: using Base = RewriterBase<TargetNode>; explicit DeclRewriterBase(std::set<Replacement>* replacements) - : Base(replacements) {} + : Base(replacements, GetCategory<DeclNode>()) {} void run(const MatchFinder::MatchResult& result) override { const DeclNode* decl = result.Nodes.getNodeAs<DeclNode>("decl"); @@ -1326,7 +1358,7 @@ using Base = RewriterBase<TargetNode>; explicit UnresolvedRewriterBase(std::set<Replacement>* replacements) - : RewriterBase<TargetNode>(replacements) {} + : RewriterBase<TargetNode>(replacements, RenameCategory::kUnresolved) {} void run(const MatchFinder::MatchResult& result) override { const TargetNode& node = Base::GetTargetNode(result); @@ -1844,13 +1876,32 @@ return result; // Supplemental data for the Blink rename rebase helper. - // TODO(dcheng): There's a lot of match rewriters missing from this list. + std::vector<const EditTracker*> all_edit_trackers{ + field_decl_rewriter.edit_tracker(), + var_decl_rewriter.edit_tracker(), + enum_member_decl_rewriter.edit_tracker(), + member_rewriter.edit_tracker(), + decl_ref_rewriter.edit_tracker(), + enum_member_ref_rewriter.edit_tracker(), + member_ref_rewriter.edit_tracker(), + function_decl_rewriter.edit_tracker(), + function_ref_rewriter.edit_tracker(), + method_decl_rewriter.edit_tracker(), + method_ref_rewriter.edit_tracker(), + method_member_rewriter.edit_tracker(), + constructor_initializer_rewriter.edit_tracker(), + unresolved_lookup_rewriter.edit_tracker(), + unresolved_member_rewriter.edit_tracker(), + unresolved_dependent_member_rewriter.edit_tracker(), + unresolved_using_value_decl_rewriter.edit_tracker(), + using_decl_rewriter.edit_tracker(), + dependent_scope_decl_ref_expr_rewriter.edit_tracker(), + cxx_dependent_scope_member_expr_rewriter.edit_tracker(), + gmock_member_rewriter.edit_tracker(), + }; llvm::outs() << "==== BEGIN TRACKED EDITS ====\n"; - field_decl_rewriter.edit_tracker().SerializeTo("var", llvm::outs()); - var_decl_rewriter.edit_tracker().SerializeTo("var", llvm::outs()); - enum_member_decl_rewriter.edit_tracker().SerializeTo("enu", llvm::outs()); - function_decl_rewriter.edit_tracker().SerializeTo("fun", llvm::outs()); - method_decl_rewriter.edit_tracker().SerializeTo("fun", llvm::outs()); + for (const EditTracker* edit_tracker : all_edit_trackers) + edit_tracker->SerializeTo(llvm::outs()); llvm::outs() << "==== END TRACKED EDITS ====\n"; // Serialization format is documented in tools/clang/scripts/run_tool.py
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids index 1aeb81a..300ea7d9 100644 --- a/tools/gritsettings/resource_ids +++ b/tools/gritsettings/resource_ids
@@ -125,6 +125,9 @@ "chrome/browser/resources/translate_internals_resources.grd": { "includes": [12560], }, + "chrome/browser/resources/webapks_ui_resources.grd": { + "includes": [12570], + }, # END chrome/browser section. # START chrome/ miscellaneous section.
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index a52ab5f..1e7d499 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -175,7 +175,7 @@ 'EarlGreyiOS': 'ios', 'GomaCanaryiOS': 'ios', 'ios-simulator': 'ios', - 'Headless Linux (dbg)': '//build/args/bots/chromium.fyi/headless_linux_dbg.gn', + 'Headless Linux (dbg)': 'headless_linux_debug_bot', 'MD Top Chrome ChromeOS material-hybrid': 'chromeos_with_codecs_debug_bot', 'MD Top Chrome ChromeOS non-material': 'chromeos_with_codecs_debug_bot', 'MD Top Chrome Win material': 'debug_bot', @@ -302,6 +302,7 @@ 'ios-device-xcode-clang': 'ios', 'ios-simulator': 'ios', 'ios-simulator-cronet': 'ios', + 'ios-simulator-eg': 'ios', 'ios-simulator-xcode-clang': 'ios', }, @@ -543,8 +544,7 @@ 'linux_chromium_dbg_32_ng': 'debug_trybot_x86', 'linux_chromium_dbg_ng': 'debug_trybot', 'linux_chromium_gn_upload': 'gn_linux_upload', - 'linux_chromium_headless_dbg': '//build/args/bots/tryserver.chromium.linux/linux_chromium_headless_dbg.gn', - 'linux_chromium_headless_rel': '//build/args/bots/tryserver.chromium.linux/linux_chromium_headless_rel.gn', + 'linux_chromium_headless_rel': 'headless_linux_release_trybot', 'linux_chromium_ozone_compile_only_ng': 'ozone_linux_release_trybot', # This is intentionally a release_bot and not a release_trybot; @@ -594,6 +594,7 @@ 'ios-device': 'ios', 'ios-device-xcode-clang': 'ios', 'ios-simulator': 'ios', + 'ios-simulator-eg': 'ios', 'ios-simulator-cronet': 'ios', 'ios-simulator-xcode-clang': 'ios', 'mac_chromium_10.10_rel_ng': 'gpu_tests_release_trybot', @@ -1263,6 +1264,14 @@ 'gn_linux_upload', 'official', 'goma', ], + 'headless_linux_debug_bot': [ + 'debug_bot', 'headless', + ], + + 'headless_linux_release_trybot': [ + 'release_trybot', 'headless', + ], + # The 'ios' config is just used for auditing. iOS bots # actually use the ios recipes, not the chromium recipe, and look # up their GN arguments via files checked in under //ios/build/bots. @@ -1714,6 +1723,10 @@ 'gn_args': 'use_system_xcode=false', }, + 'headless': { + 'args_file': '//build/args/headless.gn', + }, + 'hybrid': { 'gn_args': 'v8_target_cpu="arm" target_cpu="x86"', 'mixins': ['disable_nacl'],
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 892197b..166559b6 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -8916,11 +8916,13 @@ <action name="Media.Audible.AddTab"> <owner>mlamouri@chromium.org</owner> <description>A tab became audible.</description> + <obsolete>Removed 02/2017</obsolete> </action> <action name="Media.Audible.RemoveTab"> <owner>mlamouri@chromium.org</owner> <description>A tab is no longer audible.</description> + <obsolete>Removed 02/2017</obsolete> </action> <action name="Media.Controls.Cast">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 5048829..adde8ffb 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -5481,6 +5481,17 @@ <summary>Maximal amount of memory allocated by decoder.</summary> </histogram> +<histogram name="BrowserDialogs.ExternalProtocol.HandleState" + enum="HandleStateType"> + <owner>ramyasharma@chromium.org</owner> + <summary> + Whether or not the user checked the option in the external protocol dialog + to remember their choice of opening or not opening the specified app. + Recorded each time the user interacts with the External Protocol Dialog, + when making a decision. + </summary> +</histogram> + <histogram name="BrowserDialogs.ExternalProtocol.RememberCheckbox" enum="BooleanChecked"> <owner>dominickn@chromium.org</owner> @@ -63036,6 +63047,22 @@ <summary>Track how a profile gets signed out.</summary> </histogram> +<histogram name="Signin.TokenTable.GetAllTokensSqlStatementValidity" + enum="BooleanValid"> + <owner>msarda@chromium.org</owner> + <summary> + Counts how many times the SQL statements to get all tokens is valid. + </summary> +</histogram> + +<histogram name="Signin.TokenTable.ReadTokenFromDBResult" + enum="SigninTokenTableReadTokenFromDBResult"> + <owner>msarda@chromium.org</owner> + <summary> + Counts the results of loading a refresh token from the token database. + </summary> +</histogram> + <histogram name="Signin.UberTokenFailure" enum="GoogleServiceAuthError"> <owner>mlerman@chromium.org</owner> <summary> @@ -78968,8 +78995,8 @@ <enum name="AudioCaptureStartupResult" type="int"> <int value="0" label="OK"/> - <int value="1" label="Failed to create high latency stream"/> - <int value="2" label="Failed to open high latency stream"/> + <int value="1" label="Failed to create stream"/> + <int value="2" label="Failed to open stream"/> <int value="3" label="Never received any data"/> <int value="4" label="No data received and capture stopped within 500ms"/> </enum> @@ -82653,8 +82680,8 @@ <enum name="ContentSuggestionsUIUpdateResult2" type="int"> <int value="0" label="Success (appended)"/> <int value="1" label="Success (some suggestions replaced)"/> - <int value="6" label="Fail (all suggestions seen)"/> - <int value="7" label="Fail (updates disabled)"/> + <int value="2" label="Fail (all suggestions seen)"/> + <int value="3" label="Fail (updates disabled)"/> </enum> <enum name="ContentType" type="int"> @@ -83287,6 +83314,38 @@ <int value="786950" label="EXC_GUARD/GUARD_TYPE_FD/kGUARD_EXC_WRITE"/> <int value="851968" label="EXC_CORPSE_NOTIFY/0"/> <int value="1129345912" label="crashpad::kMachExceptionSimulated"/> + <int value="1396900608" label="SIGQUIT/0"/> + <int value="1396900864" label="SIGILL/ILL_NOOP"/> + <int value="1396900865" label="SIGILL/ILL_ILLOPC"/> + <int value="1396900866" label="SIGILL/ILL_ILLTRP"/> + <int value="1396900867" label="SIGILL/ILL_PRVOPC"/> + <int value="1396900868" label="SIGILL/ILL_ILLOPN"/> + <int value="1396900869" label="SIGILL/ILL_ILLADR"/> + <int value="1396900870" label="SIGILL/ILL_PRVREG"/> + <int value="1396900871" label="SIGILL/ILL_COPROC"/> + <int value="1396900872" label="SIGILL/ILL_BADSTK"/> + <int value="1396901120" label="SIGTRAP/0"/> + <int value="1396901121" label="SIGTRAP/TRAP_BRKPT"/> + <int value="1396901122" label="SIGTRAP/TRAP_TRACE"/> + <int value="1396901376" label="SIGABRT/0"/> + <int value="1396901632" label="SIGEMT/0"/> + <int value="1396901888" label="SIGFPE/FPE_NOOP"/> + <int value="1396901889" label="SIGFPE/FPE_FLTDIV"/> + <int value="1396901890" label="SIGFPE/FPE_FLTOVF"/> + <int value="1396901891" label="SIGFPE/FPE_FLTUND"/> + <int value="1396901892" label="SIGFPE/FPE_FLTRES"/> + <int value="1396901893" label="SIGFPE/FPE_FLTINV"/> + <int value="1396901894" label="SIGFPE/FPE_FLTSUB"/> + <int value="1396901895" label="SIGFPE/FPE_INTDIV"/> + <int value="1396901896" label="SIGFPE/FPE_INTOVF"/> + <int value="1396902400" label="SIGBUS/BUS_NOOP"/> + <int value="1396902401" label="SIGBUS/BUS_ADRALN"/> + <int value="1396902402" label="SIGBUS/BUS_ADRERR"/> + <int value="1396902403" label="SIGBUS/BUS_OBJERR"/> + <int value="1396902656" label="SIGSEGV/SEGV_NOOP"/> + <int value="1396902657" label="SIGSEGV/SEGV_MAPERR"/> + <int value="1396902658" label="SIGSEGV/SEGV_ACCERR"/> + <int value="1396902912" label="SIGSYS/0"/> </enum> <enum name="CrashpadReportPending" type="int"> @@ -86408,6 +86467,8 @@ <int value="361" label="Maximum SSL version enabled"/> <int value="362" label="Show Cast icon in the toolbar or the overflow menu."/> <int value="363" label="Enable Android Google Location Service."/> + <int value="364" label="Device sign-in screen locale"/> + <int value="365" label="Device sign-in screen keyboard layouts"/> </enum> <enum name="EnterprisePolicyInvalidations" type="int"> @@ -90867,6 +90928,9 @@ <int value="1801" label="V8TextDetector_Detect_Method"/> <int value="1802" label="CSSValueOnDemand"/> <int value="1803" label="ServiceWorkerNavigationPreload"/> + <int value="1804" label="FullscreenRequestWithPendingElement"/> + <int value="1805" + label="HTMLIFrameElementAllowfullscreenAttributeSetAfterContentLoad"/> </enum> <enum name="FetchRequestMode" type="int"> @@ -93280,6 +93344,13 @@ <int value="1" label="Observed form interaction"/> </enum> +<enum name="HandleStateType" type="int"> + <int value="0" label="Launch"/> + <int value="1" label="Checked launch"/> + <int value="2" label="Dont launch"/> + <int value="3" label="Checked dont launch"/> +</enum> + <enum name="HIDContinueScenarioType" type="int"> <summary>Possible detected devices combination on leaving dialog</summary> <int value="0" label="Pointing device only detected."/> @@ -96804,6 +96875,7 @@ <int value="323605372" label="ui-disable-compositor-animation-timelines"/> <int value="324631366" label="enable-drive-search-in-app-launcher"/> <int value="327045548" label="SafeSearchUrlReporting:enabled"/> + <int value="328722396" label="NTPCondensedLayout:disabled"/> <int value="330138076" label="enable-clear-browsing-data-counters"/> <int value="332391072" label="cs-contextual-cards-bar-integration"/> <int value="346711293" label="enable-save-password-bubble"/> @@ -97133,6 +97205,7 @@ <int value="1724800383" label="AsmJsToWebAssembly:disabled"/> <int value="1730094138" label="enable-md-storage-manager"/> <int value="1730236697" label="force-device-scale-factor"/> + <int value="1730416578" label="NTPCondensedLayout:enabled"/> <int value="1731522433" label="enable-offer-store-unmasked-wallet-cards"/> <int value="1747279677" label="disable-delegated-renderer"/> <int value="1752168018" label="enable-stale-while-revalidate"/> @@ -100146,6 +100219,7 @@ <int value="2" label="Fits, field trial is not enabled"/> <int value="3" label="Fits, field trial is enabled but does not fit"/> <int value="4" label="Fits with field trial"/> + <int value="5" label="Layout is condensed"/> </enum> <enum name="NTPLoadType" type="int"> @@ -106476,6 +106550,12 @@ <int value="12" label="Unknown"/> </enum> +<enum name="SigninTokenTableReadTokenFromDBResult" type="int"> + <int value="0" label="Success"/> + <int value="1" label="Decrypt failed"/> + <int value="2" label="Read DB failed (bad entry)"/> +</enum> + <enum name="SigninXDevicePromoEligibility" type="int"> <int value="0" label="Eligible">The user is eligible for the promo.</int> <int value="1" label="Opted Out"> @@ -110524,6 +110604,7 @@ <int value="1926101309" label="chrome://cryptohome/"/> <int value="1961263039" label="chrome://profiler/"/> <int value="1975618905" label="chrome://app-list/"/> + <int value="2040878656" label="chrome://bluetooth-internals/"/> <int value="2114840772" label="chrome://drive-internals/"/> <int value="3251925547" label="chrome://offline-internals/"/> </enum>
diff --git a/tools/perf/benchmarks/speedometer.py b/tools/perf/benchmarks/speedometer.py index 4c76788..8af1db1 100644 --- a/tools/perf/benchmarks/speedometer.py +++ b/tools/perf/benchmarks/speedometer.py
@@ -91,7 +91,6 @@ keychain_metric.KeychainMetric().AddResults(tab, results) -@benchmark.Disabled('android') # crbug.com/687681 class Speedometer(perf_benchmark.PerfBenchmark): test = SpeedometerMeasurement @@ -110,8 +109,7 @@ return ps -# crbug.com/579546 (ref), crbug.com/687681 (android) -@benchmark.Disabled('reference', 'android') +@benchmark.Disabled('reference') # crbug.com/579546 class SpeedometerIgnition(Speedometer): def SetExtraBrowserOptions(self, options): super(SpeedometerIgnition, self).SetExtraBrowserOptions(options) @@ -122,7 +120,6 @@ return 'speedometer-ignition' -@benchmark.Disabled('android') # crbug.com/687681 class SpeedometerTurbo(Speedometer): def SetExtraBrowserOptions(self, options): super(SpeedometerTurbo, self).SetExtraBrowserOptions(options)
diff --git a/tools/perf/benchmarks/v8.py b/tools/perf/benchmarks/v8.py index 6cfdc1e3..6f95a71 100644 --- a/tools/perf/benchmarks/v8.py +++ b/tools/perf/benchmarks/v8.py
@@ -227,6 +227,7 @@ possible_browser.platform.GetDeviceTypeName() == 'Nexus 5X') +@benchmark.Enabled('android') class V8MobileInfiniteScrollTurbo(V8MobileInfiniteScroll): """Measures V8 GC metrics and memory usage while scrolling the top mobile web pages and running Ignition+TurboFan.
diff --git a/tools/perf/page_sets/data/system_health_mobile.json b/tools/perf/page_sets/data/system_health_mobile.json index 2dcbdb77..e15b73f7 100644 --- a/tools/perf/page_sets/data/system_health_mobile.json +++ b/tools/perf/page_sets/data/system_health_mobile.json
@@ -1,133 +1,186 @@ { "archives": { - "system_health_mobile_000.wpr": [ - "load:search:amazon", - "load:search:baidu", - "load:search:yandex", - "load:search:taobao", - "load:search:ebay", - "load:search:yahoo" - ], - "system_health_mobile_001.wpr": [ - "load:social:tumblr", - "load:social:pinterest", - "load:social:instagram" - ], - "system_health_mobile_002.wpr": [ - "load:news:sohu", - "load:news:bbc", - "load:news:wikipedia" - ], - "system_health_mobile_003.wpr": [ - "load:media:9gag", - "load:media:google_images", - "load:media:soundcloud", - "load:media:youtube", - "load:media:dailymotion", - "load:media:flickr" - ], - "system_health_mobile_004.wpr": [ - "load:tools:maps", - "load:tools:stackoverflow", - "load:tools:dropbox", - "load:tools:weather", - "load:tools:drive", - "load:tools:docs" - ], - "system_health_mobile_005.wpr": [ - "load:games:lazors", - "load:games:bubbles", - "load:games:spychase" - ], - "system_health_mobile_006.wpr": [ - "load:news:cnn" - ], - "system_health_mobile_008.wpr": [ - "load:news:hackernews" - ], - "system_health_mobile_009.wpr": [ - "load:news:nytimes" - ], - "system_health_mobile_010.wpr": [ - "load:news:qq" - ], - "system_health_mobile_011.wpr": [ - "load:news:reddit" - ], - "system_health_mobile_013.wpr": [ - "load:news:washingtonpost" - ], - "system_health_mobile_014.wpr": [ - "browse:news:cnn" - ], - "system_health_mobile_016.wpr": [ - "browse:news:hackernews" - ], - "system_health_mobile_017.wpr": [ - "browse:news:nytimes" - ], - "system_health_mobile_018.wpr": [ - "browse:news:qq" - ], - "system_health_mobile_021.wpr": [ - "browse:news:washingtonpost" - ], - "system_health_mobile_022.wpr": [ - "load:social:twitter" - ], - "system_health_mobile_023.wpr": [ - "browse:social:twitter" - ], - "system_health_mobile_024.wpr": [ - "load:news:flipboard" - ], - "system_health_mobile_025.wpr": [ - "browse:news:flipboard" - ], - "system_health_mobile_027.wpr": [ - "browse:news:reddit" - ], - "system_health_mobile_028.wpr": [ - "load:social:facebook", - "browse:social:facebook" - ], - "system_health_mobile_029.wpr": [ - "load:search:google", - "search:portal:google" - ], - "system_health_mobile_035.wpr": [ - "browse:media:imgur", - "load:media:imgur" - ], - "system_health_mobile_037.wpr": [ - "browse:media:youtube" - ], - "system_health_mobile_040.wpr": [ - "load:media:facebook_photos", - "browse:media:facebook_photos" - ], - "system_health_mobile_042.wpr": [ - "long_running:tools:gmail-foreground", - "long_running:tools:gmail-background" - ], - "system_health_mobile_043.wpr": [ - "background:tools:gmail" - ], - "system_health_mobile_044.wpr": [ - "background:search:google" - ], - "system_health_mobile_045.wpr": [ - "background:social:facebook" - ], - "system_health_mobile_047.wpr": [ - "background:media:imgur" - ], - "system_health_mobile_048.wpr": [ - "load:tools:gmail" - ], - "system_health_mobile_052.wpr": [ - "background:news:nytimes" - ] + "background:media:imgur": { + "DEFAULT": "system_health_mobile_047.wpr" + }, + "background:news:nytimes": { + "DEFAULT": "system_health_mobile_052.wpr" + }, + "background:search:google": { + "DEFAULT": "system_health_mobile_044.wpr" + }, + "background:social:facebook": { + "DEFAULT": "system_health_mobile_045.wpr" + }, + "background:tools:gmail": { + "DEFAULT": "system_health_mobile_043.wpr" + }, + "browse:media:facebook_photos": { + "DEFAULT": "system_health_mobile_040.wpr" + }, + "browse:media:imgur": { + "DEFAULT": "system_health_mobile_035.wpr" + }, + "browse:media:youtube": { + "DEFAULT": "system_health_mobile_037.wpr" + }, + "browse:news:cnn": { + "DEFAULT": "system_health_mobile_014.wpr" + }, + "browse:news:flipboard": { + "DEFAULT": "system_health_mobile_025.wpr" + }, + "browse:news:hackernews": { + "DEFAULT": "system_health_mobile_016.wpr" + }, + "browse:news:nytimes": { + "DEFAULT": "system_health_mobile_017.wpr" + }, + "browse:news:qq": { + "DEFAULT": "system_health_mobile_018.wpr" + }, + "browse:news:reddit": { + "DEFAULT": "system_health_mobile_027.wpr" + }, + "browse:news:washingtonpost": { + "DEFAULT": "system_health_mobile_021.wpr" + }, + "browse:social:facebook": { + "DEFAULT": "system_health_mobile_028.wpr" + }, + "browse:social:twitter": { + "DEFAULT": "system_health_mobile_023.wpr" + }, + "load:games:bubbles": { + "DEFAULT": "system_health_mobile_005.wpr" + }, + "load:games:lazors": { + "DEFAULT": "system_health_mobile_005.wpr" + }, + "load:games:spychase": { + "DEFAULT": "system_health_mobile_005.wpr" + }, + "load:media:9gag": { + "DEFAULT": "system_health_mobile_003.wpr" + }, + "load:media:dailymotion": { + "DEFAULT": "system_health_mobile_003.wpr" + }, + "load:media:facebook_photos": { + "DEFAULT": "system_health_mobile_040.wpr" + }, + "load:media:flickr": { + "DEFAULT": "system_health_mobile_003.wpr" + }, + "load:media:google_images": { + "DEFAULT": "system_health_mobile_003.wpr" + }, + "load:media:imgur": { + "DEFAULT": "system_health_mobile_035.wpr" + }, + "load:media:soundcloud": { + "DEFAULT": "system_health_mobile_003.wpr" + }, + "load:media:youtube": { + "DEFAULT": "system_health_mobile_003.wpr" + }, + "load:news:bbc": { + "DEFAULT": "system_health_mobile_002.wpr" + }, + "load:news:cnn": { + "DEFAULT": "system_health_mobile_006.wpr" + }, + "load:news:flipboard": { + "DEFAULT": "system_health_mobile_024.wpr" + }, + "load:news:hackernews": { + "DEFAULT": "system_health_mobile_008.wpr" + }, + "load:news:nytimes": { + "DEFAULT": "system_health_mobile_009.wpr" + }, + "load:news:qq": { + "DEFAULT": "system_health_mobile_010.wpr" + }, + "load:news:reddit": { + "DEFAULT": "system_health_mobile_011.wpr" + }, + "load:news:sohu": { + "DEFAULT": "system_health_mobile_002.wpr" + }, + "load:news:washingtonpost": { + "DEFAULT": "system_health_mobile_013.wpr" + }, + "load:news:wikipedia": { + "DEFAULT": "system_health_mobile_002.wpr" + }, + "load:search:amazon": { + "DEFAULT": "system_health_mobile_000.wpr" + }, + "load:search:baidu": { + "DEFAULT": "system_health_mobile_000.wpr" + }, + "load:search:ebay": { + "DEFAULT": "system_health_mobile_000.wpr" + }, + "load:search:google": { + "DEFAULT": "system_health_mobile_029.wpr" + }, + "load:search:taobao": { + "DEFAULT": "system_health_mobile_000.wpr" + }, + "load:search:yahoo": { + "DEFAULT": "system_health_mobile_000.wpr" + }, + "load:search:yandex": { + "DEFAULT": "system_health_mobile_000.wpr" + }, + "load:social:facebook": { + "DEFAULT": "system_health_mobile_028.wpr" + }, + "load:social:instagram": { + "DEFAULT": "system_health_mobile_001.wpr" + }, + "load:social:pinterest": { + "DEFAULT": "system_health_mobile_001.wpr" + }, + "load:social:tumblr": { + "DEFAULT": "system_health_mobile_001.wpr" + }, + "load:social:twitter": { + "DEFAULT": "system_health_mobile_022.wpr" + }, + "load:tools:docs": { + "DEFAULT": "system_health_mobile_004.wpr" + }, + "load:tools:drive": { + "DEFAULT": "system_health_mobile_004.wpr" + }, + "load:tools:dropbox": { + "DEFAULT": "system_health_mobile_004.wpr" + }, + "load:tools:gmail": { + "DEFAULT": "system_health_mobile_048.wpr" + }, + "load:tools:maps": { + "DEFAULT": "system_health_mobile_004.wpr" + }, + "load:tools:stackoverflow": { + "DEFAULT": "system_health_mobile_004.wpr" + }, + "load:tools:weather": { + "DEFAULT": "system_health_mobile_004.wpr" + }, + "long_running:tools:gmail-background": { + "DEFAULT": "system_health_mobile_042.wpr" + }, + "long_running:tools:gmail-foreground": { + "DEFAULT": "system_health_mobile_042.wpr" + }, + "search:portal:google": { + "DEFAULT": "system_health_mobile_029.wpr" + } }, - "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating." -} \ No newline at end of file + "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.", + "platform_specific": true +}
diff --git a/tools/perf/page_sets/data/tough_path_rendering_cases.json b/tools/perf/page_sets/data/tough_path_rendering_cases.json index 8a134ce..1f886b36 100644 --- a/tools/perf/page_sets/data/tough_path_rendering_cases.json +++ b/tools/perf/page_sets/data/tough_path_rendering_cases.json
@@ -1,12 +1,17 @@ { - "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.", "archives": { - "tough_path_rendering_cases_001.wpr": [ - "https://testdrive-archive.azurewebsites.net/performance/chalkboard/", - "http://www.craftymind.com/factory/guimark2/HTML5ChartingTest.html" - ], "tough_path_rendering_cases_000.wpr": [ "http://ie.microsoft.com/testdrive/Performance/Chalkboard/" + ], + "tough_path_rendering_cases_001.wpr": [ + "http://www.craftymind.com/factory/guimark2/HTML5ChartingTest.html" + ], + "tough_path_rendering_cases_002.wpr": [ + "MotionMark Canvas Stroke Shapes", + "https://testdrive-archive.azurewebsites.net/performance/chalkboard/", + "GUIMark Vector Chart Test", + "MotionMark Canvas Fill Shapes" ] - } + }, + "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating." } \ No newline at end of file
diff --git a/tools/perf/page_sets/data/tough_path_rendering_cases_002.wpr.sha1 b/tools/perf/page_sets/data/tough_path_rendering_cases_002.wpr.sha1 new file mode 100644 index 0000000..34d6f18 --- /dev/null +++ b/tools/perf/page_sets/data/tough_path_rendering_cases_002.wpr.sha1
@@ -0,0 +1 @@ +8bffbefa55186d96d1b4bfc0487157492e7336f6 \ No newline at end of file
diff --git a/tools/perf/page_sets/system_health/system_health_story.py b/tools/perf/page_sets/system_health/system_health_story.py index 7104f40..5ae3fe1b 100644 --- a/tools/perf/page_sets/system_health/system_health_story.py +++ b/tools/perf/page_sets/system_health/system_health_story.py
@@ -67,6 +67,7 @@ ABSTRACT_STORY = True SUPPORTED_PLATFORMS = platforms.ALL_PLATFORMS TAGS = None + PLATFORM_SPECIFIC = False def __init__(self, story_set, take_memory_measurement): case, group, _ = self.NAME.split(':') @@ -79,7 +80,8 @@ shared_page_state_class=_SystemHealthSharedState, page_set=story_set, name=self.NAME, url=self.URL, tags=tags, credentials_path='../data/credentials.json', - grouping_keys={'case': case, 'group': group}) + grouping_keys={'case': case, 'group': group}, + platform_specific=self.PLATFORM_SPECIFIC) self._take_memory_measurement = take_memory_measurement @classmethod
diff --git a/tools/perf/page_sets/tough_path_rendering_cases.py b/tools/perf/page_sets/tough_path_rendering_cases.py index 3b7ac0b1..626b545 100644 --- a/tools/perf/page_sets/tough_path_rendering_cases.py +++ b/tools/perf/page_sets/tough_path_rendering_cases.py
@@ -6,7 +6,6 @@ class ToughPathRenderingCasesPage(page_module.Page): - def RunPageInteractions(self, action_runner): with action_runner.CreateInteraction('ClickStart'): action_runner.Wait(10) @@ -31,12 +30,18 @@ archive_data_file='data/tough_path_rendering_cases.json', cloud_storage_bucket=story.PARTNER_BUCKET) - urls_list = [ - 'http://www.craftymind.com/factory/guimark2/HTML5ChartingTest.html' + page_list = [ + ('GUIMark Vector Chart Test', + 'http://www.craftymind.com/factory/guimark2/HTML5ChartingTest.html'), + ('MotionMark Canvas Fill Shapes', + 'http://rawgit.com/WebKit/webkit/master/PerformanceTests/MotionMark/developer.html?test-name=Fillshapes&test-interval=20&display=minimal&tiles=big&controller=fixed&frame-rate=50&kalman-process-error=1&kalman-measurement-error=4&time-measurement=performance&suite-name=Canvassuite&complexity=1000'), # pylint: disable=line-too-long + ('MotionMark Canvas Stroke Shapes', + 'http://rawgit.com/WebKit/webkit/master/PerformanceTests/MotionMark/developer.html?test-name=Strokeshapes&test-interval=20&display=minimal&tiles=big&controller=fixed&frame-rate=50&kalman-process-error=1&kalman-measurement-error=4&time-measurement=performance&suite-name=Canvassuite&complexity=1000'), # pylint: disable=line-too-long ] - for url in urls_list: - self.AddStory(ToughPathRenderingCasesPage(url, self)) + for name, url in page_list: + self.AddStory(ToughPathRenderingCasesPage(name=name, url=url, + page_set=self)) # Chalkboard content linked from # http://ie.microsoft.com/testdrive/Performance/Chalkboard/.
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn index 243e57f..bc9223a5 100644 --- a/ui/android/BUILD.gn +++ b/ui/android/BUILD.gn
@@ -42,6 +42,10 @@ "ui_android_jni_registrar.h", "view_android.cc", "view_android.h", + "view_client.cc", + "view_client.h", + "view_root.cc", + "view_root.h", "window_android.cc", "window_android.h", "window_android_compositor.h", @@ -81,6 +85,7 @@ sources = [ "java/src/org/chromium/ui/OverscrollRefreshHandler.java", "java/src/org/chromium/ui/base/ViewAndroidDelegate.java", + "java/src/org/chromium/ui/base/ViewRoot.java", "java/src/org/chromium/ui/base/WindowAndroid.java", "java/src/org/chromium/ui/display/DisplayAndroidManager.java", "java/src/org/chromium/ui/resources/ResourceManager.java", @@ -176,6 +181,7 @@ "java/src/org/chromium/ui/base/SelectFileDialog.java", "java/src/org/chromium/ui/base/TouchDevice.java", "java/src/org/chromium/ui/base/ViewAndroidDelegate.java", + "java/src/org/chromium/ui/base/ViewRoot.java", "java/src/org/chromium/ui/base/WindowAndroid.java", "java/src/org/chromium/ui/display/DisplayAndroid.java", "java/src/org/chromium/ui/display/DisplayAndroidManager.java", @@ -246,6 +252,7 @@ "overscroll_refresh_unittest.cc", "resources/resource_manager_impl_unittest.cc", "run_all_unittests.cc", + "view_android_unittest.cc", ] deps = [ ":android",
diff --git a/ui/android/delegated_frame_host_android.cc b/ui/android/delegated_frame_host_android.cc index 88cc36a..2f31c5a 100644 --- a/ui/android/delegated_frame_host_android.cc +++ b/ui/android/delegated_frame_host_android.cc
@@ -78,7 +78,7 @@ DelegatedFrameHostAndroid::~DelegatedFrameHostAndroid() { DestroyDelegatedContent(); surface_factory_.reset(); - UnregisterFrameSinkHierarchy(); + DetachFromCompositor(); surface_manager_->InvalidateFrameSinkId(frame_sink_id_); background_layer_->RemoveFromParent(); } @@ -203,22 +203,21 @@ UpdateBackgroundLayer(); } -void DelegatedFrameHostAndroid::RegisterFrameSinkHierarchy( - const cc::FrameSinkId& parent_id) { - if (registered_parent_frame_sink_id_.is_valid()) - UnregisterFrameSinkHierarchy(); - registered_parent_frame_sink_id_ = parent_id; +void DelegatedFrameHostAndroid::AttachToCompositor( + WindowAndroidCompositor* compositor) { + if (registered_parent_compositor_) + DetachFromCompositor(); surface_manager_->RegisterSurfaceFactoryClient(frame_sink_id_, this); - surface_manager_->RegisterFrameSinkHierarchy(parent_id, frame_sink_id_); + compositor->AddChildFrameSink(frame_sink_id_); + registered_parent_compositor_ = compositor; } -void DelegatedFrameHostAndroid::UnregisterFrameSinkHierarchy() { - if (!registered_parent_frame_sink_id_.is_valid()) +void DelegatedFrameHostAndroid::DetachFromCompositor() { + if (!registered_parent_compositor_) return; surface_manager_->UnregisterSurfaceFactoryClient(frame_sink_id_); - surface_manager_->UnregisterFrameSinkHierarchy( - registered_parent_frame_sink_id_, frame_sink_id_); - registered_parent_frame_sink_id_ = cc::FrameSinkId(); + registered_parent_compositor_->RemoveChildFrameSink(frame_sink_id_); + registered_parent_compositor_ = nullptr; } void DelegatedFrameHostAndroid::ReturnResources(
diff --git a/ui/android/delegated_frame_host_android.h b/ui/android/delegated_frame_host_android.h index 2e3ba78..a58e530 100644 --- a/ui/android/delegated_frame_host_android.h +++ b/ui/android/delegated_frame_host_android.h
@@ -69,8 +69,8 @@ // Called when this DFH is attached/detached from a parent browser compositor // and needs to be attached to the surface hierarchy. - void RegisterFrameSinkHierarchy(const cc::FrameSinkId& parent_id); - void UnregisterFrameSinkHierarchy(); + void AttachToCompositor(WindowAndroidCompositor* compositor); + void DetachFromCompositor(); private: // cc::SurfaceFactoryClient implementation. @@ -85,7 +85,7 @@ cc::SurfaceManager* surface_manager_; std::unique_ptr<cc::SurfaceIdAllocator> surface_id_allocator_; - cc::FrameSinkId registered_parent_frame_sink_id_; + WindowAndroidCompositor* registered_parent_compositor_ = nullptr; Client* client_; std::unique_ptr<cc::SurfaceFactory> surface_factory_;
diff --git a/ui/android/java/src/org/chromium/ui/base/ViewRoot.java b/ui/android/java/src/org/chromium/ui/base/ViewRoot.java new file mode 100644 index 0000000..291c3af --- /dev/null +++ b/ui/android/java/src/org/chromium/ui/base/ViewRoot.java
@@ -0,0 +1,104 @@ +// 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. + +package org.chromium.ui.base; + +import android.view.MotionEvent; + +import org.chromium.base.annotations.JNINamespace; + +/** + * Class used to forward view, input events down to native. + * TODO(jinsukkim): Hook this up to UI event forwarding flow and substitute WindowAndroid. + */ +@JNINamespace("ui") +public class ViewRoot { + + private final WindowAndroid mWindowAndroid; + + // The corresponding native instance. This class can only be used while + // the native instance is alive. + // This is initialized lazily. Use {@link getNativePtr()} rather than + // accessing it directly. + private long mNativeView; + + public static ViewRoot create(WindowAndroid window) { + if (window == null) throw new IllegalArgumentException("WindowAndroid should not be null"); + return new ViewRoot(window); + } + + private ViewRoot(WindowAndroid window) { + mWindowAndroid = window; + } + + public WindowAndroid getWindowAndroid() { + return mWindowAndroid; + } + + public boolean onTouchEvent(MotionEvent event, boolean isTouchHandleEvent) { + final int pointerCount = event.getPointerCount(); + + float[] touchMajor = {event.getTouchMajor(), + pointerCount > 1 ? event.getTouchMajor(1) : 0}; + float[] touchMinor = {event.getTouchMinor(), + pointerCount > 1 ? event.getTouchMinor(1) : 0}; + + for (int i = 0; i < 2; i++) { + if (touchMajor[i] < touchMinor[i]) { + float tmp = touchMajor[i]; + touchMajor[i] = touchMinor[i]; + touchMinor[i] = tmp; + } + } + + return nativeOnTouchEvent(getNativePtr(), event, + event.getEventTime(), event.getActionMasked(), + pointerCount, event.getHistorySize(), event.getActionIndex(), + event.getX(), event.getY(), + pointerCount > 1 ? event.getX(1) : 0, + pointerCount > 1 ? event.getY(1) : 0, + event.getPointerId(0), pointerCount > 1 ? event.getPointerId(1) : -1, + touchMajor[0], touchMajor[1], + touchMinor[0], touchMinor[1], + event.getOrientation(), pointerCount > 1 ? event.getOrientation(1) : 0, + event.getAxisValue(MotionEvent.AXIS_TILT), + pointerCount > 1 ? event.getAxisValue(MotionEvent.AXIS_TILT, 1) : 0, + event.getRawX(), event.getRawY(), + event.getToolType(0), + pointerCount > 1 ? event.getToolType(1) : MotionEvent.TOOL_TYPE_UNKNOWN, + event.getButtonState(), + event.getMetaState(), + isTouchHandleEvent); + } + + public long getNativePtr() { + if (mNativeView == 0) mNativeView = nativeInit(mWindowAndroid.getNativePointer()); + return mNativeView; + } + + public void destroy() { + if (mNativeView != 0) { + nativeDestroy(mNativeView); + mNativeView = 0; + } + } + + private native long nativeInit(long windowNativePointer); + private native void nativeDestroy(long nativeViewRoot); + + // All touch events (including flings, scrolls etc) accept coordinates in physical pixels. + private native boolean nativeOnTouchEvent( + long nativeViewRoot, MotionEvent event, + long timeMs, int action, int pointerCount, int historySize, int actionIndex, + float x0, float y0, float x1, float y1, + int pointerId0, int pointerId1, + float touchMajor0, float touchMajor1, + float touchMinor0, float touchMinor1, + float orientation0, float orientation1, + float tilt0, float tilt1, + float rawX, float rawY, + int androidToolType0, int androidToolType1, + int androidButtonState, int androidMetaState, + boolean isTouchHandleEvent); +}
diff --git a/ui/android/ui_android_jni_registrar.cc b/ui/android/ui_android_jni_registrar.cc index 3c02c50..1534cd5 100644 --- a/ui/android/ui_android_jni_registrar.cc +++ b/ui/android/ui_android_jni_registrar.cc
@@ -10,6 +10,7 @@ #include "ui/android/resources/resource_manager_impl.h" #include "ui/android/screen_android.h" #include "ui/android/view_android.h" +#include "ui/android/view_root.h" #include "ui/android/window_android.h" namespace ui { @@ -17,6 +18,7 @@ static base::android::RegistrationMethod kAndroidRegisteredMethods[] = { {"DisplayAndroidManager", ui::RegisterScreenAndroid}, {"ResourceManager", ui::ResourceManagerImpl::RegisterResourceManager}, + {"ViewRoot", ui::RegisterViewRoot}, {"WindowAndroid", WindowAndroid::RegisterWindowAndroid}, };
diff --git a/ui/android/view_android.cc b/ui/android/view_android.cc index 6c55a7bf..43f084f 100644 --- a/ui/android/view_android.cc +++ b/ui/android/view_android.cc
@@ -18,6 +18,7 @@ using base::android::JavaRef; using base::android::ScopedJavaLocalRef; +// ViewAndroid::ScopedAndroidView ViewAndroid::ScopedAnchorView::ScopedAnchorView( JNIEnv* env, const JavaRef<jobject>& jview, @@ -68,44 +69,65 @@ return view_.get(env); } -ViewAndroid::ViewAndroid(const JavaRef<jobject>& delegate) - : parent_(nullptr) - , delegate_(base::android::AttachCurrentThread(), - delegate.obj()) {} - -ViewAndroid::ViewAndroid() : parent_(nullptr) {} +// ViewAndroid +ViewAndroid::ViewAndroid(ViewClient* client) : parent_(nullptr), + client_(client) {} +ViewAndroid::ViewAndroid() : ViewAndroid(nullptr) {} ViewAndroid::~ViewAndroid() { RemoveFromParent(); - for (std::list<ViewAndroid*>::iterator it = children_.begin(); - it != children_.end(); it++) { - DCHECK_EQ((*it)->parent_, this); - (*it)->parent_ = nullptr; - } + auto children_copy = std::list<ViewAndroid*>(children_); + for (auto& child : children_copy) + RemoveChild(child); } void ViewAndroid::SetDelegate(const JavaRef<jobject>& delegate) { + // A ViewAndroid may have its own delegate or otherwise will + // use the next available parent's delegate. JNIEnv* env = base::android::AttachCurrentThread(); delegate_ = JavaObjectWeakGlobalRef(env, delegate); } void ViewAndroid::AddChild(ViewAndroid* child) { DCHECK(child); + DCHECK(!child->IsViewRoot()); // ViewRoot cannot be a child. DCHECK(std::find(children_.begin(), children_.end(), child) == children_.end()); + // The new child goes to the top, which is the end of the list. children_.push_back(child); if (child->parent_) child->RemoveFromParent(); child->parent_ = this; } +void ViewAndroid::MoveToTop(ViewAndroid* child) { + DCHECK(child); + auto it = std::find(children_.begin(), children_.end(), child); + DCHECK(it != children_.end()); + + // Top element is placed at the end of the list. + if (*it != children_.back()) + children_.splice(children_.rbegin().base(), children_, it); +} + void ViewAndroid::RemoveFromParent() { if (parent_) parent_->RemoveChild(this); } +void ViewAndroid::SetLayout(int x, + int y, + int width, + int height, + bool match_parent) { + DCHECK(!match_parent || (x == 0 && y == 0 && width == 0 && height == 0)); + origin_.SetPoint(x, y); + size_.SetSize(width, height); + match_parent_ = match_parent; +} + ViewAndroid::ScopedAnchorView ViewAndroid::AcquireAnchorView() { ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate()); if (delegate.is_null()) @@ -116,15 +138,19 @@ env, Java_ViewAndroidDelegate_acquireView(env, delegate), delegate); } +float ViewAndroid::GetDipScale() { + return display::Screen::GetScreen() + ->GetDisplayNearestWindow(this) + .device_scale_factor(); +} + void ViewAndroid::SetAnchorRect(const JavaRef<jobject>& anchor, const gfx::RectF& bounds) { ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate()); if (delegate.is_null()) return; - float scale = display::Screen::GetScreen() - ->GetDisplayNearestWindow(this) - .device_scale_factor(); + float scale = GetDipScale(); int left_margin = std::round(bounds.x() * scale); int top_margin = std::round((content_offset().y() + bounds.y()) * scale); JNIEnv* env = base::android::AttachCurrentThread(); @@ -175,6 +201,14 @@ layer_ = layer; } +ViewAndroid* ViewAndroid::GetViewRoot() { + return parent_ ? parent_->GetViewRoot() : nullptr; +} + +bool ViewAndroid::IsViewRoot() { + return GetViewRoot() == this; +} + bool ViewAndroid::StartDragAndDrop(const JavaRef<jstring>& jtext, const JavaRef<jobject>& jimage) { ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate()); @@ -185,4 +219,26 @@ jimage); } +bool ViewAndroid::OnTouchEventInternal(const MotionEventData& event) { + if (!children_.empty()) { + const MotionEventData& e = + origin_.IsOrigin() ? event : event.Offset(-origin_.x(), -origin_.y()); + + for (auto it = children_.rbegin(); it != children_.rend(); ++it) { + bool matched = (*it)->match_parent_; + if (!matched) { + gfx::Rect bound((*it)->origin_, (*it)->size_); + matched = bound.Contains(e.GetX(), e.GetY()); + } + if (matched && (*it)->OnTouchEventInternal(e)) + return true; + } + } + + if (client_ && client_->OnTouchEvent(event)) + return true; + + return false; +} + } // namespace ui
diff --git a/ui/android/view_android.h b/ui/android/view_android.h index 68adf34..e446048 100644 --- a/ui/android/view_android.h +++ b/ui/android/view_android.h
@@ -10,6 +10,7 @@ #include "base/android/jni_weak_ref.h" #include "base/memory/ref_counted.h" #include "ui/android/ui_android_export.h" +#include "ui/android/view_client.h" #include "ui/gfx/geometry/rect_f.h" namespace cc { @@ -22,6 +23,8 @@ // A simple container for a UI layer. // At the root of the hierarchy is a WindowAndroid, when attached. +// TODO(jinsukkim): Replace WindowAndroid with ViewRoot for the root of the +// view hierarchy. See https://crbug.com/671401 class UI_ANDROID_EXPORT ViewAndroid { public: // Stores an anchored view to delete itself at the end of its lifetime @@ -54,9 +57,7 @@ // Default copy/assign disabled by move constructor. }; - // A ViewAndroid may have its own delegate or otherwise will - // use the next available parent's delegate. - ViewAndroid(const base::android::JavaRef<jobject>& delegate); + explicit ViewAndroid(ViewClient* client); ViewAndroid(); virtual ~ViewAndroid(); @@ -75,18 +76,29 @@ // if disconnected. virtual WindowAndroid* GetWindowAndroid() const; + // Returns |ViewRoot| of this hierarchy. |null| if the hierarchy isn't + // attached to a |ViewRoot|. + virtual ViewAndroid* GetViewRoot(); + // Used to return and set the layer for this view. May be |null|. cc::Layer* GetLayer() const; void SetLayer(scoped_refptr<cc::Layer> layer); void SetDelegate(const base::android::JavaRef<jobject>& delegate); - // Adds this view as a child of another view. + // Adds a child to this view. void AddChild(ViewAndroid* child); + // Move the give child ViewAndroid to the top of the list + // so that it can be the first responder of events. + void MoveToTop(ViewAndroid* child); + // Detaches this view from its parent. void RemoveFromParent(); + // Set the layout relative to parent. Used to do hit testing against events. + void SetLayout(int x, int y, int width, int height, bool match_parent); + bool StartDragAndDrop(const base::android::JavaRef<jstring>& jtext, const base::android::JavaRef<jobject>& jimage); @@ -98,9 +110,18 @@ base::android::ScopedJavaLocalRef<jobject> GetContainerView(); protected: + // Internal implementation of ViewClient forwarding calls to the interface. + bool OnTouchEventInternal(const MotionEventData& event); + + // Virtual for testing. + virtual float GetDipScale(); + ViewAndroid* parent_; private: + // Returns true only if this is of type |ViewRoot|. + bool IsViewRoot(); + void RemoveChild(ViewAndroid* child); // Returns the Java delegate for this view. This is used to delegate work @@ -109,10 +130,19 @@ const base::android::ScopedJavaLocalRef<jobject> GetViewAndroidDelegate() const; + // The child view at the back of the list receives event first. std::list<ViewAndroid*> children_; scoped_refptr<cc::Layer> layer_; JavaObjectWeakGlobalRef delegate_; - gfx::Vector2dF content_offset_; // in CSS pixel + ViewClient* const client_; + + // Basic view layout information. Used to do hit testing deciding whether + // the passed events should be processed by the view. + gfx::Point origin_; // In parent's coordinate space. + gfx::Size size_; + bool match_parent_; // Bounds matches that of the parent if true. + + gfx::Vector2dF content_offset_; // In CSS pixel. DISALLOW_COPY_AND_ASSIGN(ViewAndroid); };
diff --git a/ui/android/view_android_unittest.cc b/ui/android/view_android_unittest.cc new file mode 100644 index 0000000..e4500b5 --- /dev/null +++ b/ui/android/view_android_unittest.cc
@@ -0,0 +1,167 @@ +// 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 "testing/gtest/include/gtest/gtest.h" +#include "ui/android/view_root.h" + +namespace ui { + +using base::android::JavaParamRef; + +class TestViewRoot : public ViewRoot { + public: + TestViewRoot() : ViewRoot(0L) {} + float GetDipScale() override { return 1.f; } +}; + +class TestViewClient : public ViewClient { + public: + TestViewClient() : handle_event_(true), + called_(false) {} + + void SetHandleEvent(bool handle_event) { handle_event_ = handle_event; } + bool OnTouchEvent(const MotionEventData& event) override { + called_ = true; + return handle_event_; + } + + bool EventHandled() { return called_ && handle_event_; } + void Reset() { called_ = false; } + + private: + bool handle_event_; // Marks as event was consumed. True by default. + bool called_; +}; + +class ViewAndroidBoundsTest : public testing::Test { + public: + ViewAndroidBoundsTest() : view1_(&client1_), + view2_(&client2_), + view3_(&client3_) {} + void Reset() { + client1_.Reset(); + client2_.Reset(); + client3_.Reset(); + } + + void GenerateTouchEventAt(float x, float y) { + root_.OnTouchEvent(nullptr, + JavaParamRef<jobject>(nullptr), + JavaParamRef<jobject>(nullptr), + 0L, // time + 0, 1, 0, 0, + x, y, 0.f, 0.f, // pos + 0, 0, // pointer_id + 0.f, 0.f, 0.f, 0.f, // touch + 0.f, 0.f, 0.f, 0.f, + 0.f, 0.f, + 0, 0, 0, 0, + false); + } + + void ExpectHit(const TestViewClient& hitClient) { + TestViewClient* clients[3] = { &client1_, &client2_, &client3_ }; + for (auto& client : clients) { + if (&hitClient == client) + EXPECT_TRUE(client->EventHandled()); + else + EXPECT_FALSE(client->EventHandled()); + } + Reset(); + } + + TestViewRoot root_; + TestViewClient client1_; + TestViewClient client2_; + TestViewClient client3_; + ViewAndroid view1_; + ViewAndroid view2_; + ViewAndroid view3_; +}; + +TEST_F(ViewAndroidBoundsTest, MatchesViewInFront) { + view1_.SetLayout(50, 50, 400, 600, false); + view2_.SetLayout(50, 50, 400, 600, false); + root_.AddChild(&view2_); + root_.AddChild(&view1_); + + GenerateTouchEventAt(100.f, 100.f); + ExpectHit(client1_); + + // View 2 moves up to the top, and events should hit it from now. + root_.MoveToTop(&view2_); + GenerateTouchEventAt(100.f, 100.f); + ExpectHit(client2_); +} + +TEST_F(ViewAndroidBoundsTest, MatchesViewArea) { + view1_.SetLayout(50, 50, 200, 200, false); + view2_.SetLayout(20, 20, 400, 600, false); + + root_.AddChild(&view2_); + root_.AddChild(&view1_); + + // Falls within |view1_|'s bounds + GenerateTouchEventAt(100.f, 100.f); + ExpectHit(client1_); + + // Falls within |view2_|'s bounds + GenerateTouchEventAt(300.f, 400.f); + ExpectHit(client2_); +} + +TEST_F(ViewAndroidBoundsTest, MatchesViewAfterMove) { + view1_.SetLayout(50, 50, 200, 200, false); + view2_.SetLayout(20, 20, 400, 600, false); + root_.AddChild(&view2_); + root_.AddChild(&view1_); + + GenerateTouchEventAt(100.f, 100.f); + ExpectHit(client1_); + + view1_.SetLayout(150, 150, 200, 200, false); + GenerateTouchEventAt(100.f, 100.f); + ExpectHit(client2_); +} + +TEST_F(ViewAndroidBoundsTest, MatchesViewSizeOfkMatchParent) { + view1_.SetLayout(20, 20, 400, 600, false); + view3_.SetLayout(0, 0, 0, 0, true); // match parent + view2_.SetLayout(50, 50, 200, 200, false); + + root_.AddChild(&view1_); + root_.AddChild(&view2_); + view1_.AddChild(&view3_); + + GenerateTouchEventAt(100.f, 100.f); + ExpectHit(client2_); + + GenerateTouchEventAt(300.f, 400.f); + ExpectHit(client3_); + + client3_.SetHandleEvent(false); + GenerateTouchEventAt(300.f, 400.f); + ExpectHit(client1_); +} + +TEST_F(ViewAndroidBoundsTest, MatchesViewsWithOffset) { + view1_.SetLayout(10, 20, 150, 100, false); + view2_.SetLayout(20, 30, 40, 30, false); + view3_.SetLayout(70, 30, 40, 30, false); + + root_.AddChild(&view1_); + view1_.AddChild(&view2_); + view1_.AddChild(&view3_); + + GenerateTouchEventAt(70, 30); + ExpectHit(client1_); + + GenerateTouchEventAt(40, 60); + ExpectHit(client2_); + + GenerateTouchEventAt(100, 70); + ExpectHit(client3_); +} + +} // namespace ui
diff --git a/ui/android/view_client.cc b/ui/android/view_client.cc new file mode 100644 index 0000000..b2442b1 --- /dev/null +++ b/ui/android/view_client.cc
@@ -0,0 +1,129 @@ +// 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 "ui/android/view_client.h" + +namespace ui { + +MotionEventData::MotionEventData(float dip_scale, + jobject jevent, + long time, + int action, + int pointer_count, + int history_size, + int action_index, + float pos_x0, + float pos_y0, + float pos_x1, + float pos_y1, + int pointer_id_0, + int pointer_id_1, + float touch_major_0, + float touch_major_1, + float touch_minor_0, + float touch_minor_1, + float orientation_0, + float orientation_1, + float tilt_0, + float tilt_1, + float raw_pos_x, + float raw_pos_y, + int tool_type_0, + int tool_type_1, + int button_state, + int meta_state, + bool is_touch_handle_event) : + dip_scale_(dip_scale), + jevent_(jevent), + time_(time), + action_(action), + pointer_count_(pointer_count), + history_size_(history_size), + action_index_(action_index), + pos_x0_(pos_x0), + pos_y0_(pos_y0), + pos_x1_(pos_x1), + pos_y1_(pos_y1), + pointer_id_0_(pointer_id_0), + pointer_id_1_(pointer_id_1), + touch_major_0_(touch_major_0), + touch_major_1_(touch_major_1), + touch_minor_0_(touch_minor_0), + touch_minor_1_(touch_minor_1), + orientation_0_(orientation_0), + orientation_1_(orientation_1), + tilt_0_(tilt_0), + tilt_1_(tilt_1), + raw_pos_x_(raw_pos_x), + raw_pos_y_(raw_pos_y), + tool_type_0_(tool_type_0), + tool_type_1_(tool_type_1), + button_state_(button_state), + meta_state_(meta_state), + is_touch_handle_event_(is_touch_handle_event) {} + +MotionEventData::MotionEventData(const MotionEventData& other) : + dip_scale_(other.dip_scale_), + jevent_(other.jevent_), + time_(other.time_), + action_(other.action_), + pointer_count_(other.pointer_count_), + history_size_(other.history_size_), + action_index_(other.action_index_), + pos_x0_(other.pos_x0_), + pos_y0_(other.pos_y0_), + pos_x1_(other.pos_x1_), + pos_y1_(other.pos_y1_), + pointer_id_0_(other.pointer_id_0_), + pointer_id_1_(other.pointer_id_1_), + touch_major_0_(other.touch_major_0_), + touch_major_1_(other.touch_major_1_), + touch_minor_0_(other.touch_minor_0_), + touch_minor_1_(other.touch_minor_1_), + orientation_0_(other.orientation_0_), + orientation_1_(other.orientation_1_), + tilt_0_(other.tilt_0_), + tilt_1_(other.tilt_1_), + raw_pos_x_(other.raw_pos_x_), + raw_pos_y_(other.raw_pos_y_), + tool_type_0_(other.tool_type_0_), + tool_type_1_(other.tool_type_1_), + button_state_(other.button_state_), + meta_state_(other.meta_state_), + is_touch_handle_event_(other.is_touch_handle_event_) {} + +MotionEventData MotionEventData::Offset(float delta_x, float delta_y) const { + return MotionEventData(dip_scale_, + jevent_, + time_, + action_, + pointer_count_, + history_size_, + action_index_, + pos_x0_ + delta_x, + pos_y0_ + delta_y, + pos_x1_ + delta_x, + pos_y1_ + delta_y, + pointer_id_0_, + pointer_id_1_, + touch_major_0_, + touch_major_1_, + touch_minor_0_, + touch_minor_1_, + orientation_0_, + orientation_1_, + tilt_0_, + tilt_1_, + raw_pos_x_, + raw_pos_y_, + tool_type_0_, + tool_type_1_, + button_state_, + meta_state_, + is_touch_handle_event_); +} + +bool ViewClient::OnTouchEvent(const MotionEventData& event) { return false; } + +} // namespace ui
diff --git a/ui/android/view_client.h b/ui/android/view_client.h new file mode 100644 index 0000000..fb7f79c --- /dev/null +++ b/ui/android/view_client.h
@@ -0,0 +1,103 @@ +// 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 UI_ANDROID_VIEW_CLIENT_H_ +#define UI_ANDROID_VIEW_CLIENT_H_ + +#include <jni.h> + +#include "ui/android/ui_android_export.h" + +namespace ui { + +// Container of motion event data. Used when traversing views along their +// hierarchy. Actual motion event object will be constructed right before +// it is used in the |ViewClient| implementation to avoid creating multiple +// |MotionEventAndroid| instances. +struct MotionEventData { + MotionEventData(float dip_scale, + jobject jevent, + long time, + int action, + int pointer_count, + int history_size, + int action_index, + float pos_x0, + float pos_y0, + float pos_x1, + float pos_y1, + int pointer_id_0, + int pointer_id_1, + float touch_major_0, + float touch_major_1, + float touch_minor_0, + float touch_minor_1, + float orientation_0, + float orientation_1, + float tilt_0, + float tilt_1, + float raw_pos_x, + float raw_pos_y, + int tool_type_0, + int tool_type_1, + int button_state, + int meta_state, + bool is_touch_handle_event); + + MotionEventData(const MotionEventData& other); + + // Returns a new |MotionEventData| object whose position is offset + // by a given delta. + MotionEventData Offset(float delta_x, float delta_y) const; + + float GetX() const { return pos_x0_ / dip_scale_; } + float GetY() const { return pos_y0_ / dip_scale_; } + + const float dip_scale_; + const jobject jevent_; + const long time_; // ms + const int action_; + const int pointer_count_; + const int history_size_; + const int action_index_; + + const float pos_x0_; // in pixel unit + const float pos_y0_; + const float pos_x1_; + const float pos_y1_; + + const int pointer_id_0_; + const int pointer_id_1_; + const float touch_major_0_; + const float touch_major_1_; + const float touch_minor_0_; + const float touch_minor_1_; + const float orientation_0_; + const float orientation_1_; + const float tilt_0_; + const float tilt_1_; + const float raw_pos_x_; + const float raw_pos_y_; + const int tool_type_0_; + const int tool_type_1_; + const int button_state_; + const int meta_state_; + const bool is_touch_handle_event_; +}; + +// Client interface used to forward events from Java to native views. +// Calls are dispatched to its children along the hierarchy of ViewAndroid. +// Use bool return type to stop propagating the call i.e. overriden method +// should return true to indicate that the event was handled and stop +// the processing. +// Note: Not in use yet. Will be hooked up together with ViewRoot. +// See https://crbug.com/671401. +class UI_ANDROID_EXPORT ViewClient { + public: + virtual bool OnTouchEvent(const MotionEventData& event); +}; + +} // namespace ui + +#endif // UI_ANDROID_VIEW_CLIENT_H_
diff --git a/ui/android/view_root.cc b/ui/android/view_root.cc new file mode 100644 index 0000000..1a1f977 --- /dev/null +++ b/ui/android/view_root.cc
@@ -0,0 +1,106 @@ +// 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 "ui/android/view_root.h" + +#include "jni/ViewRoot_jni.h" + +namespace ui { + +using base::android::JavaParamRef; + +ViewRoot::ViewRoot(jlong window_android_ptr) { + WindowAndroid* window_android = + reinterpret_cast<WindowAndroid*>(window_android_ptr); + window_ = window_android; + + // ViewRoot simply accepts all events and lets the hit testing + // start from its children. + SetLayout(0, 0, 0, 0, true); +} + +ViewAndroid* ViewRoot::GetViewRoot() { + return this; +} + +WindowAndroid* ViewRoot::GetWindowAndroid() const { + return window_; +} + +void ViewRoot::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) { + delete this; +} + +jboolean ViewRoot::OnTouchEvent(JNIEnv* env, + const JavaParamRef<jobject>& obj, + const JavaParamRef<jobject>& motion_event, + jlong time_ms, + jint android_action, + jint pointer_count, + jint history_size, + jint action_index, + jfloat pos_x_0, + jfloat pos_y_0, + jfloat pos_x_1, + jfloat pos_y_1, + jint pointer_id_0, + jint pointer_id_1, + jfloat touch_major_0, + jfloat touch_major_1, + jfloat touch_minor_0, + jfloat touch_minor_1, + jfloat orientation_0, + jfloat orientation_1, + jfloat tilt_0, + jfloat tilt_1, + jfloat raw_pos_x, + jfloat raw_pos_y, + jint android_tool_type_0, + jint android_tool_type_1, + jint android_button_state, + jint android_meta_state, + jboolean is_touch_handle_event) { + MotionEventData event(GetDipScale(), + motion_event.obj(), + time_ms, + android_action, + pointer_count, + history_size, + action_index, + pos_x_0, + pos_y_0, + pos_x_1, + pos_y_1, + pointer_id_0, + pointer_id_1, + touch_major_0, + touch_major_1, + touch_minor_0, + touch_minor_1, + orientation_0, + orientation_1, + tilt_0, + tilt_1, + raw_pos_x, + raw_pos_y, + android_tool_type_0, + android_tool_type_1, + android_button_state, + android_meta_state, + is_touch_handle_event); + return OnTouchEventInternal(event); +} + +// static +jlong Init(JNIEnv* env, + const JavaParamRef<jobject>& obj, + jlong window_android_ptr) { + return reinterpret_cast<intptr_t>(new ViewRoot(window_android_ptr)); +} + +bool RegisterViewRoot(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +} // namespace ui
diff --git a/ui/android/view_root.h b/ui/android/view_root.h new file mode 100644 index 0000000..49007fa4 --- /dev/null +++ b/ui/android/view_root.h
@@ -0,0 +1,71 @@ +// 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 UI_ANDROID_VIEW_ROOT_H_ +#define UI_ANDROID_VIEW_ROOT_H_ + +#include <jni.h> + +#include "base/android/scoped_java_ref.h" +#include "ui/android/ui_android_export.h" +#include "ui/android/view_android.h" + +namespace ui { + +// ViewRoot is the root of a ViewAndroid tree. +// TODO(jinsukkim): Hook this up to UI event forwarding flow and +// substitute WindowAndroid. See https://crbug.com/671401 +class UI_ANDROID_EXPORT ViewRoot : public ViewAndroid { + public: + explicit ViewRoot(jlong window_android_ptr); + + // ViewAndroid overrides. + WindowAndroid* GetWindowAndroid() const override; + ViewAndroid* GetViewRoot() override; + + void Destroy(JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj); + + jboolean OnTouchEvent( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + const base::android::JavaParamRef<jobject>& motion_event, + jlong time_ms, + jint android_action, + jint pointer_count, + jint history_size, + jint action_index, + jfloat pos_x_0, + jfloat pos_y_0, + jfloat pos_x_1, + jfloat pos_y_1, + jint pointer_id_0, + jint pointer_id_1, + jfloat touch_major_0, + jfloat touch_major_1, + jfloat touch_minor_0, + jfloat touch_minor_1, + jfloat orientation_0, + jfloat orientation_1, + jfloat tilt_0, + jfloat tilt_1, + jfloat raw_pos_x, + jfloat raw_pos_y, + jint android_tool_type_0, + jint android_tool_type_1, + jint android_button_state, + jint android_meta_state, + jboolean is_touch_handle_event); + + private: + WindowAndroid* window_; + + DISALLOW_COPY_AND_ASSIGN(ViewRoot); +}; + +bool RegisterViewRoot(JNIEnv* env); + +} // namespace ui + +#endif // UI_ANDROID_VIEW_ROOT_H_
diff --git a/ui/android/window_android_compositor.h b/ui/android/window_android_compositor.h index 7dfa349..12cc1dd 100644 --- a/ui/android/window_android_compositor.h +++ b/ui/android/window_android_compositor.h
@@ -30,6 +30,8 @@ virtual void SetNeedsAnimate() = 0; virtual ResourceManager& GetResourceManager() = 0; virtual cc::FrameSinkId GetFrameSinkId() = 0; + virtual void AddChildFrameSink(const cc::FrameSinkId& frame_sink_id) = 0; + virtual void RemoveChildFrameSink(const cc::FrameSinkId& frame_sink_id) = 0; }; } // namespace ui
diff --git a/ui/base/cocoa/base_view.mm b/ui/base/cocoa/base_view.mm index 47ccca9..2172fec 100644 --- a/ui/base/cocoa/base_view.mm +++ b/ui/base/cocoa/base_view.mm
@@ -82,6 +82,10 @@ // This method left intentionally blank. } +- (void)tabletEvent:(NSEvent*)theEvent { + // This method left intentionally blank. +} + - (void)mouseDown:(NSEvent*)theEvent { dragging_ = YES; [self mouseEvent:theEvent]; @@ -200,4 +204,8 @@ return new_rect; } +- (void)tabletProximity:(NSEvent*)theEvent { + [self tabletEvent:theEvent]; +} + @end
diff --git a/ui/base/ime/chromeos/input_method_manager.h b/ui/base/ime/chromeos/input_method_manager.h index 69531425..2ad022dd 100644 --- a/ui/base/ime/chromeos/input_method_manager.h +++ b/ui/base/ime/chromeos/input_method_manager.h
@@ -213,6 +213,18 @@ virtual bool ReplaceEnabledInputMethods( const std::vector<std::string>& new_active_input_method_ids) = 0; + // Sets the currently allowed input methods (e.g. due to policy). Invalid + // input method ids are ignored. Passing an empty vector means that all + // input methods are allowed, which is the default. When allowed input + // methods are set, these are also automatically enabled. + virtual bool SetAllowedInputMethods( + const std::vector<std::string>& allowed_input_method_ids) = 0; + + // Returns the currently allowed input methods, as set by + // SetAllowedInputMethodIds. An empty vector means that all input methods + // are allowed. + virtual const std::vector<std::string>& GetAllowedInputMethods() = 0; + protected: friend base::RefCounted<InputMethodManager::State>;
diff --git a/ui/base/ime/chromeos/mock_input_method_manager.cc b/ui/base/ime/chromeos/mock_input_method_manager.cc index 0e4c6230..60af4b6 100644 --- a/ui/base/ime/chromeos/mock_input_method_manager.cc +++ b/ui/base/ime/chromeos/mock_input_method_manager.cc
@@ -92,6 +92,17 @@ return true; } +bool MockInputMethodManager::State::SetAllowedInputMethods( + const std::vector<std::string>& new_allowed_input_method_ids) { + allowed_input_method_ids_ = new_allowed_input_method_ids; + return true; +} + +const std::vector<std::string>& +MockInputMethodManager::State::GetAllowedInputMethods() { + return allowed_input_method_ids_; +} + MockInputMethodManager::State::~State() {} MockInputMethodManager::MockInputMethodManager() {}
diff --git a/ui/base/ime/chromeos/mock_input_method_manager.h b/ui/base/ime/chromeos/mock_input_method_manager.h index 586d9e5..5e5c596 100644 --- a/ui/base/ime/chromeos/mock_input_method_manager.h +++ b/ui/base/ime/chromeos/mock_input_method_manager.h
@@ -53,6 +53,9 @@ InputMethodDescriptor GetCurrentInputMethod() const override; bool ReplaceEnabledInputMethods( const std::vector<std::string>& new_active_input_method_ids) override; + bool SetAllowedInputMethods( + const std::vector<std::string>& new_allowed_input_method_ids) override; + const std::vector<std::string>& GetAllowedInputMethods() override; // The active input method ids cache (actually default only) std::vector<std::string> active_input_method_ids; @@ -62,6 +65,9 @@ ~State() override; private: + // Allowed input methods ids + std::vector<std::string> allowed_input_method_ids_; + DISALLOW_COPY_AND_ASSIGN(State); };
diff --git a/ui/events/keycodes/dom/dom_key_data.inc b/ui/events/keycodes/dom/dom_key_data.inc index 2eaa8a7b..c598dcdd 100644 --- a/ui/events/keycodes/dom/dom_key_data.inc +++ b/ui/events/keycodes/dom/dom_key_data.inc
@@ -279,6 +279,7 @@ DOM_KEY_MAP("MailForward", MAIL_FORWARD, 0x0A02), DOM_KEY_MAP("MailReply", MAIL_REPLY, 0x0A03), DOM_KEY_MAP("MailSend", MAIL_SEND, 0x0A04), + DOM_KEY_MAP("MediaClose", MEDIA_CLOSE, 0x0D5B), DOM_KEY_MAP("MediaFastForward", MEDIA_FAST_FORWARD, 0x0D2C), DOM_KEY_MAP("MediaPause", MEDIA_PAUSE, 0x0D2E), DOM_KEY_MAP("MediaPlay", MEDIA_PLAY, 0x0D2F), @@ -316,11 +317,9 @@ // Key Enum Value DOM_KEY_MAP("AudioBalanceLeft", AUDIO_BALANCE_LEFT, 0x0D01), DOM_KEY_MAP("AudioBalanceRight", AUDIO_BALANCE_RIGHT, 0x0D02), - DOM_KEY_MAP("AudioBassDown", AUDIO_BASS_DOWN, 0x0E01), DOM_KEY_MAP("AudioBassBoostDown", AUDIO_BASS_BOOST_DOWN, 0x0D03), DOM_KEY_MAP("AudioBassBoostToggle", AUDIO_BASS_BOOST_TOGGLE, 0x0E02), DOM_KEY_MAP("AudioBassBoostUp", AUDIO_BASS_BOOST_UP, 0x0D04), - DOM_KEY_MAP("AudioBassUp", AUDIO_BASS_UP, 0x0E03), DOM_KEY_MAP("AudioFaderFront", AUDIO_FADER_FRONT, 0x0D05), DOM_KEY_MAP("AudioFaderRear", AUDIO_FADER_REAR, 0x0D06), DOM_KEY_MAP("AudioSurroundModeNext",AUDIO_SURROUND_MODE_NEXT, 0x0D07), @@ -349,15 +348,13 @@ // ====================================================== // Key Enum Value - // "LaunchCalculator" is equivalent to "Launch Application 2": - DOM_KEY_MAP("LaunchCalculator", LAUNCH_CALCULATOR, 0x0B01), + DOM_KEY_MAP("LaunchApplication1", LAUNCH_MY_COMPUTER, 0x0B06), + DOM_KEY_MAP("LaunchApplication2", LAUNCH_CALCULATOR, 0x0B01), DOM_KEY_MAP("LaunchCalendar", LAUNCH_CALENDAR, 0x0B02), DOM_KEY_MAP("LaunchContacts", LAUNCH_CONTACTS, 0x0B0C), DOM_KEY_MAP("LaunchMail", LAUNCH_MAIL, 0x0B03), DOM_KEY_MAP("LaunchMediaPlayer", LAUNCH_MEDIA_PLAYER, 0x0B04), DOM_KEY_MAP("LaunchMusicPlayer", LAUNCH_MUSIC_PLAYER, 0x0B05), - // "LaunchMyComputer" is equivalent to "Launch Application 1": - DOM_KEY_MAP("LaunchMyComputer", LAUNCH_MY_COMPUTER, 0x0B06), DOM_KEY_MAP("LaunchPhone", LAUNCH_PHONE, 0x0B0D), DOM_KEY_MAP("LaunchScreenSaver", LAUNCH_SCREEN_SAVER, 0x0B07), DOM_KEY_MAP("LaunchSpreadsheet", LAUNCH_SPREADSHEET, 0x0B08),
diff --git a/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc b/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc index e318ccb..b7e4cb3 100644 --- a/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc +++ b/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc
@@ -823,8 +823,8 @@ {{DomCode::NUMPAD0, EF_NONE, XKB_KEY_KP_0, '0'}, VKEY_NUMPAD0}, {{DomCode::NUMPAD9, EF_NONE, XKB_KEY_KP_9, '9'}, VKEY_NUMPAD9}, // Verify AltGr+V & AltGr+W on de(neo) layout. - {{DomCode::US_W, EF_ALTGR_DOWN, XKB_KEY_BackSpace, 8}, VKEY_BACKSPACE}, - {{DomCode::US_V, EF_ALTGR_DOWN, XKB_KEY_Return, 13}, VKEY_ENTER}, + {{DomCode::US_W, EF_ALTGR_DOWN, XKB_KEY_BackSpace, 8}, VKEY_BACK}, + {{DomCode::US_V, EF_ALTGR_DOWN, XKB_KEY_Return, 13}, VKEY_RETURN}, }; for (const auto& e : kVkeyTestCase) { SCOPED_TRACE(static_cast<int>(e.test.dom_code));
diff --git a/ui/gfx/canvas.cc b/ui/gfx/canvas.cc index 8d43cb63..c2e62df 100644 --- a/ui/gfx/canvas.cc +++ b/ui/gfx/canvas.cc
@@ -167,16 +167,16 @@ } // Make a shader for the bitmap with an origin of the box we'll draw. - cc::PaintFlags paint; - paint.setShader(cc::WrapSkShader(SkShader::MakeBitmapShader( + cc::PaintFlags flags; + flags.setShader(cc::WrapSkShader(SkShader::MakeBitmapShader( *dots, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode))); - DrawRect(RectF(rect.x(), rect.y(), rect.width(), 1), paint); + DrawRect(RectF(rect.x(), rect.y(), rect.width(), 1), flags); DrawRect(RectF(rect.x(), rect.y() + rect.height() - 1, rect.width(), 1), - paint); - DrawRect(RectF(rect.x(), rect.y(), 1, rect.height()), paint); + flags); + DrawRect(RectF(rect.x(), rect.y(), 1, rect.height()), flags); DrawRect(RectF(rect.x() + rect.width() - 1, rect.y(), 1, rect.height()), - paint); + flags); } float Canvas::UndoDeviceScaleFactor() { @@ -249,11 +249,11 @@ } void Canvas::FillRect(const Rect& rect, SkColor color, SkBlendMode mode) { - cc::PaintFlags paint; - paint.setColor(color); - paint.setStyle(cc::PaintFlags::kFill_Style); - paint.setBlendMode(mode); - DrawRect(rect, paint); + cc::PaintFlags flags; + flags.setColor(color); + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setBlendMode(mode); + DrawRect(rect, flags); } void Canvas::DrawRect(const Rect& rect, SkColor color) { @@ -269,32 +269,32 @@ } void Canvas::DrawRect(const RectF& rect, SkColor color, SkBlendMode mode) { - cc::PaintFlags paint; - paint.setColor(color); - paint.setStyle(cc::PaintFlags::kStroke_Style); + cc::PaintFlags flags; + flags.setColor(color); + flags.setStyle(cc::PaintFlags::kStroke_Style); // Set a stroke width of 0, which will put us down the stroke rect path. If // we set a stroke width of 1, for example, this will internally create a // path and fill it, which causes problems near the edge of the canvas. - paint.setStrokeWidth(SkIntToScalar(0)); - paint.setBlendMode(mode); + flags.setStrokeWidth(SkIntToScalar(0)); + flags.setBlendMode(mode); - DrawRect(rect, paint); + DrawRect(rect, flags); } -void Canvas::DrawRect(const Rect& rect, const cc::PaintFlags& paint) { - DrawRect(RectF(rect), paint); +void Canvas::DrawRect(const Rect& rect, const cc::PaintFlags& flags) { + DrawRect(RectF(rect), flags); } -void Canvas::DrawRect(const RectF& rect, const cc::PaintFlags& paint) { - canvas_->drawRect(RectFToSkRect(rect), paint); +void Canvas::DrawRect(const RectF& rect, const cc::PaintFlags& flags) { + canvas_->drawRect(RectFToSkRect(rect), flags); } -void Canvas::DrawPoint(const Point& p1, const cc::PaintFlags& paint) { - DrawPoint(PointF(p1), paint); +void Canvas::DrawPoint(const Point& p1, const cc::PaintFlags& flags) { + DrawPoint(PointF(p1), flags); } -void Canvas::DrawPoint(const PointF& p1, const cc::PaintFlags& paint) { - canvas_->drawPoint(SkFloatToScalar(p1.x()), SkFloatToScalar(p1.y()), paint); +void Canvas::DrawPoint(const PointF& p1, const cc::PaintFlags& flags) { + canvas_->drawPoint(SkFloatToScalar(p1.x()), SkFloatToScalar(p1.y()), flags); } void Canvas::DrawLine(const Point& p1, const Point& p2, SkColor color) { @@ -302,54 +302,54 @@ } void Canvas::DrawLine(const PointF& p1, const PointF& p2, SkColor color) { - cc::PaintFlags paint; - paint.setColor(color); - paint.setStrokeWidth(SkIntToScalar(1)); - DrawLine(p1, p2, paint); + cc::PaintFlags flags; + flags.setColor(color); + flags.setStrokeWidth(SkIntToScalar(1)); + DrawLine(p1, p2, flags); } void Canvas::DrawLine(const Point& p1, const Point& p2, - const cc::PaintFlags& paint) { - DrawLine(PointF(p1), PointF(p2), paint); + const cc::PaintFlags& flags) { + DrawLine(PointF(p1), PointF(p2), flags); } void Canvas::DrawLine(const PointF& p1, const PointF& p2, - const cc::PaintFlags& paint) { + const cc::PaintFlags& flags) { canvas_->drawLine(SkFloatToScalar(p1.x()), SkFloatToScalar(p1.y()), - SkFloatToScalar(p2.x()), SkFloatToScalar(p2.y()), paint); + SkFloatToScalar(p2.x()), SkFloatToScalar(p2.y()), flags); } void Canvas::DrawCircle(const Point& center_point, int radius, - const cc::PaintFlags& paint) { - DrawCircle(PointF(center_point), radius, paint); + const cc::PaintFlags& flags) { + DrawCircle(PointF(center_point), radius, flags); } void Canvas::DrawCircle(const PointF& center_point, float radius, - const cc::PaintFlags& paint) { + const cc::PaintFlags& flags) { canvas_->drawCircle(SkFloatToScalar(center_point.x()), SkFloatToScalar(center_point.y()), - SkFloatToScalar(radius), paint); + SkFloatToScalar(radius), flags); } void Canvas::DrawRoundRect(const Rect& rect, int radius, - const cc::PaintFlags& paint) { - DrawRoundRect(RectF(rect), radius, paint); + const cc::PaintFlags& flags) { + DrawRoundRect(RectF(rect), radius, flags); } void Canvas::DrawRoundRect(const RectF& rect, float radius, - const cc::PaintFlags& paint) { + const cc::PaintFlags& flags) { canvas_->drawRoundRect(RectFToSkRect(rect), SkFloatToScalar(radius), - SkFloatToScalar(radius), paint); + SkFloatToScalar(radius), flags); } -void Canvas::DrawPath(const SkPath& path, const cc::PaintFlags& paint) { - canvas_->drawPath(path, paint); +void Canvas::DrawPath(const SkPath& path, const cc::PaintFlags& flags) { + canvas_->drawPath(path, flags); } void Canvas::DrawFocusRect(const Rect& rect) { @@ -363,30 +363,30 @@ void Canvas::DrawSolidFocusRect(const RectF& rect, SkColor color, float thickness) { - cc::PaintFlags paint; - paint.setColor(color); - paint.setStrokeWidth(SkFloatToScalar(thickness)); - paint.setStyle(cc::PaintFlags::kStroke_Style); + cc::PaintFlags flags; + flags.setColor(color); + flags.setStrokeWidth(SkFloatToScalar(thickness)); + flags.setStyle(cc::PaintFlags::kStroke_Style); gfx::RectF draw_rect = rect; draw_rect.Inset(gfx::InsetsF(thickness / 2)); - DrawRect(draw_rect, paint); + DrawRect(draw_rect, flags); } void Canvas::DrawImageInt(const ImageSkia& image, int x, int y) { - cc::PaintFlags paint; - DrawImageInt(image, x, y, paint); + cc::PaintFlags flags; + DrawImageInt(image, x, y, flags); } void Canvas::DrawImageInt(const ImageSkia& image, int x, int y, uint8_t a) { - cc::PaintFlags paint; - paint.setAlpha(a); - DrawImageInt(image, x, y, paint); + cc::PaintFlags flags; + flags.setAlpha(a); + DrawImageInt(image, x, y, flags); } void Canvas::DrawImageInt(const ImageSkia& image, int x, int y, - const cc::PaintFlags& paint) { + const cc::PaintFlags& flags) { const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_); if (image_rep.is_null()) return; @@ -396,10 +396,8 @@ ScopedCanvas scoper(this); canvas_->scale(SkFloatToScalar(1.0f / bitmap_scale), SkFloatToScalar(1.0f / bitmap_scale)); - canvas_->drawBitmap(bitmap, - SkFloatToScalar(x * bitmap_scale), - SkFloatToScalar(y * bitmap_scale), - &paint); + canvas_->drawBitmap(bitmap, SkFloatToScalar(x * bitmap_scale), + SkFloatToScalar(y * bitmap_scale), &flags); } void Canvas::DrawImageInt(const ImageSkia& image, @@ -412,9 +410,9 @@ int dest_w, int dest_h, bool filter) { - cc::PaintFlags p; - DrawImageInt(image, src_x, src_y, src_w, src_h, dest_x, dest_y, - dest_w, dest_h, filter, p); + cc::PaintFlags flags; + DrawImageInt(image, src_x, src_y, src_w, src_h, dest_x, dest_y, dest_w, + dest_h, filter, flags); } void Canvas::DrawImageInt(const ImageSkia& image, @@ -427,13 +425,13 @@ int dest_w, int dest_h, bool filter, - const cc::PaintFlags& paint) { + const cc::PaintFlags& flags) { const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_); if (image_rep.is_null()) return; bool remove_image_scale = true; DrawImageIntHelper(image_rep, src_x, src_y, src_w, src_h, dest_x, dest_y, - dest_w, dest_h, filter, paint, remove_image_scale); + dest_w, dest_h, filter, flags, remove_image_scale); } void Canvas::DrawImageIntInPixel(const ImageSkiaRep& image_rep, @@ -442,7 +440,7 @@ int dest_w, int dest_h, bool filter, - const cc::PaintFlags& paint) { + const cc::PaintFlags& flags) { int src_x = 0; int src_y = 0; int src_w = image_rep.pixel_width(); @@ -451,24 +449,24 @@ // (already scaled) |image_rep| at a 1:1 scale with the canvas. bool remove_image_scale = false; DrawImageIntHelper(image_rep, src_x, src_y, src_w, src_h, dest_x, dest_y, - dest_w, dest_h, filter, paint, remove_image_scale); + dest_w, dest_h, filter, flags, remove_image_scale); } void Canvas::DrawImageInPath(const ImageSkia& image, int x, int y, const SkPath& path, - const cc::PaintFlags& paint) { + const cc::PaintFlags& original_flags) { const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_); if (image_rep.is_null()) return; SkMatrix matrix; matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y)); - cc::PaintFlags p(paint); - p.setShader( + cc::PaintFlags flags(original_flags); + flags.setShader( CreateImageRepShader(image_rep, SkShader::kRepeat_TileMode, matrix)); - canvas_->drawPath(path, p); + canvas_->drawPath(path, flags); } void Canvas::DrawStringRect(const base::string16& text, @@ -513,10 +511,10 @@ if (!IntersectsClipRect(dest_rect)) return; - cc::PaintFlags paint; + cc::PaintFlags flags; if (InitPaintFlagsForTiling(image, src_x, src_y, tile_scale_x, tile_scale_y, - dest_x, dest_y, &paint)) - canvas_->drawRect(dest_rect, paint); + dest_x, dest_y, &flags)) + canvas_->drawRect(dest_rect, flags); } bool Canvas::InitPaintFlagsForTiling(const ImageSkia& image, @@ -526,7 +524,7 @@ float tile_scale_y, int dest_x, int dest_y, - cc::PaintFlags* paint) { + cc::PaintFlags* flags) { const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_); if (image_rep.is_null()) return false; @@ -537,9 +535,9 @@ shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y)); shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y)); - paint->setShader(CreateImageRepShader(image_rep, SkShader::kRepeat_TileMode, + flags->setShader(CreateImageRepShader(image_rep, SkShader::kRepeat_TileMode, shader_scale)); - paint->setBlendMode(SkBlendMode::kSrcOver); + flags->setBlendMode(SkBlendMode::kSrcOver); return true; } @@ -562,7 +560,7 @@ int dest_w, int dest_h, bool filter, - const cc::PaintFlags& paint, + const cc::PaintFlags& original_flags, bool remove_image_scale) { DLOG_ASSERT(src_x + src_w < std::numeric_limits<int16_t>::max() && src_y + src_h < std::numeric_limits<int16_t>::max()); @@ -591,14 +589,14 @@ shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y)); shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y)); - cc::PaintFlags p(paint); - p.setFilterQuality(filter ? kLow_SkFilterQuality : kNone_SkFilterQuality); - p.setShader(CreateImageRepShaderForScale( + cc::PaintFlags flags(original_flags); + flags.setFilterQuality(filter ? kLow_SkFilterQuality : kNone_SkFilterQuality); + flags.setShader(CreateImageRepShaderForScale( image_rep, SkShader::kRepeat_TileMode, shader_scale, remove_image_scale ? image_rep.scale() : 1.f)); // The rect will be filled by the bitmap. - canvas_->drawRect(dest_rect, p); + canvas_->drawRect(dest_rect, flags); } } // namespace gfx
diff --git a/ui/gfx/canvas.h b/ui/gfx/canvas.h index e6aef31..9303fb2d 100644 --- a/ui/gfx/canvas.h +++ b/ui/gfx/canvas.h
@@ -258,21 +258,21 @@ // NOTE: if you need a single pixel line, use DrawLine. void DrawRect(const RectF& rect, SkColor color, SkBlendMode mode); - // Draws the given rectangle with the given |paint| parameters. + // Draws the given rectangle with the given |flags| parameters. // DEPRECATED in favor of the RectF version below. // TODO(funkysidd): Remove this (http://crbug.com/553726) - void DrawRect(const Rect& rect, const cc::PaintFlags& paint); + void DrawRect(const Rect& rect, const cc::PaintFlags& flags); - // Draws the given rectangle with the given |paint| parameters. - void DrawRect(const RectF& rect, const cc::PaintFlags& paint); + // Draws the given rectangle with the given |flags| parameters. + void DrawRect(const RectF& rect, const cc::PaintFlags& flags); - // Draw the given point with the given |paint| parameters. + // Draw the given point with the given |flags| parameters. // DEPRECATED in favor of the RectF version below. // TODO(funkysidd): Remove this (http://crbug.com/553726) - void DrawPoint(const Point& p, const cc::PaintFlags& paint); + void DrawPoint(const Point& p, const cc::PaintFlags& flags); - // Draw the given point with the given |paint| parameters. - void DrawPoint(const PointF& p, const cc::PaintFlags& paint); + // Draw the given point with the given |flags| parameters. + void DrawPoint(const PointF& p, const cc::PaintFlags& flags); // Draws a single pixel line with the specified color. // DEPRECATED in favor of the RectF version below. @@ -282,41 +282,41 @@ // Draws a single pixel line with the specified color. void DrawLine(const PointF& p1, const PointF& p2, SkColor color); - // Draws a line with the given |paint| parameters. + // Draws a line with the given |flags| parameters. // DEPRECATED in favor of the RectF version below. // TODO(funkysidd): Remove this (http://crbug.com/553726) - void DrawLine(const Point& p1, const Point& p2, const cc::PaintFlags& paint); + void DrawLine(const Point& p1, const Point& p2, const cc::PaintFlags& flags); - // Draws a line with the given |paint| parameters. + // Draws a line with the given |flags| parameters. void DrawLine(const PointF& p1, const PointF& p2, - const cc::PaintFlags& paint); + const cc::PaintFlags& flags); - // Draws a circle with the given |paint| parameters. + // Draws a circle with the given |flags| parameters. // DEPRECATED in favor of the RectF version below. // TODO(funkysidd): Remove this (http://crbug.com/553726) void DrawCircle(const Point& center_point, int radius, - const cc::PaintFlags& paint); + const cc::PaintFlags& flags); - // Draws a circle with the given |paint| parameters. + // Draws a circle with the given |flags| parameters. void DrawCircle(const PointF& center_point, float radius, - const cc::PaintFlags& paint); + const cc::PaintFlags& flags); // Draws the given rectangle with rounded corners of |radius| using the - // given |paint| parameters. DEPRECATED in favor of the RectF version below. + // given |flags| parameters. DEPRECATED in favor of the RectF version below. // TODO(mgiuca): Remove this (http://crbug.com/553726). - void DrawRoundRect(const Rect& rect, int radius, const cc::PaintFlags& paint); + void DrawRoundRect(const Rect& rect, int radius, const cc::PaintFlags& flags); // Draws the given rectangle with rounded corners of |radius| using the - // given |paint| parameters. + // given |flags| parameters. void DrawRoundRect(const RectF& rect, float radius, - const cc::PaintFlags& paint); + const cc::PaintFlags& flags); - // Draws the given path using the given |paint| parameters. - void DrawPath(const SkPath& path, const cc::PaintFlags& paint); + // Draws the given path using the given |flags| parameters. + void DrawPath(const SkPath& path, const cc::PaintFlags& flags); // Draws an image with the origin at the specified location. The upper left // corner of the bitmap is rendered at the specified location. @@ -324,19 +324,19 @@ // Thus, x is 2 pixels if canvas scale = 2 & |x| = 1. void DrawImageInt(const ImageSkia&, int x, int y); - // Helper for DrawImageInt(..., paint) that constructs a temporary paint and - // calls paint.setAlpha(alpha). + // Helper for DrawImageInt(..., flags) that constructs a temporary flags and + // calls flags.setAlpha(alpha). void DrawImageInt(const ImageSkia&, int x, int y, uint8_t alpha); // Draws an image with the origin at the specified location, using the - // specified paint. The upper left corner of the bitmap is rendered at the + // specified flags. The upper left corner of the bitmap is rendered at the // specified location. // Parameters are specified relative to current canvas scale not in pixels. // Thus, |x| is 2 pixels if canvas scale = 2 & |x| = 1. void DrawImageInt(const ImageSkia& image, int x, int y, - const cc::PaintFlags& paint); + const cc::PaintFlags& flags); // Draws a portion of an image in the specified location. The src parameters // correspond to the region of the bitmap to draw in the region defined @@ -370,7 +370,7 @@ int dest_w, int dest_h, bool filter, - const cc::PaintFlags& paint); + const cc::PaintFlags& flags); // Same as the DrawImageInt functions above. Difference being this does not // do any scaling, i.e. it does not scale the output by the device scale @@ -383,7 +383,7 @@ int dest_w, int dest_h, bool filter, - const cc::PaintFlags& paint); + const cc::PaintFlags& flags); // Draws an |image| with the top left corner at |x| and |y|, clipped to // |path|. @@ -393,7 +393,7 @@ int x, int y, const SkPath& path, - const cc::PaintFlags& paint); + const cc::PaintFlags& flags); // Draws text with the specified color, fonts and location. The text is // aligned to the left, vertically centered, clipped to the region. If the @@ -449,7 +449,7 @@ int w, int h); - // Helper for TileImageInt(). Initializes |paint| for tiling |image| with the + // Helper for TileImageInt(). Initializes |flags| for tiling |image| with the // given parameters. Returns false if the provided image does not have a // representation for the current scale. bool InitPaintFlagsForTiling(const ImageSkia& image, @@ -459,7 +459,7 @@ float tile_scale_y, int dest_x, int dest_y, - cc::PaintFlags* paint); + cc::PaintFlags* flags); // Apply transformation on the canvas. void Transform(const Transform& transform); @@ -492,7 +492,7 @@ int dest_w, int dest_h, bool filter, - const cc::PaintFlags& paint, + const cc::PaintFlags& flags, bool remove_image_scale); // The device scale factor at which drawing on this canvas occurs.
diff --git a/ui/gfx/harfbuzz_font_skia.cc b/ui/gfx/harfbuzz_font_skia.cc index 602b02a..4f5d307 100644 --- a/ui/gfx/harfbuzz_font_skia.cc +++ b/ui/gfx/harfbuzz_font_skia.cc
@@ -13,7 +13,6 @@ #include "base/lazy_instance.h" #include "base/logging.h" #include "base/macros.h" -#include "cc/paint/paint_flags.h" #include "third_party/skia/include/core/SkTypeface.h" #include "ui/gfx/render_text.h" #include "ui/gfx/skia_util.h" @@ -34,7 +33,7 @@ struct FontData { FontData(GlyphCache* glyph_cache) : glyph_cache_(glyph_cache) {} - cc::PaintFlags paint_; + SkPaint paint_; GlyphCache* glyph_cache_; }; @@ -53,12 +52,12 @@ // Outputs the |width| and |extents| of the glyph with index |codepoint| in // |paint|'s font. -void GetGlyphWidthAndExtents(cc::PaintFlags* paint, +void GetGlyphWidthAndExtents(SkPaint* paint, hb_codepoint_t codepoint, hb_position_t* width, hb_glyph_extents_t* extents) { DCHECK_LE(codepoint, std::numeric_limits<uint16_t>::max()); - paint->setTextEncoding(cc::PaintFlags::kGlyphID_TextEncoding); + paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); SkScalar sk_width; SkRect sk_bounds; @@ -90,8 +89,8 @@ bool exists = cache->count(unicode) != 0; if (!exists) { - cc::PaintFlags* paint = &font_data->paint_; - paint->setTextEncoding(cc::PaintFlags::kUTF32_TextEncoding); + SkPaint* paint = &font_data->paint_; + paint->setTextEncoding(SkPaint::kUTF32_TextEncoding); paint->textToGlyphs(&unicode, sizeof(hb_codepoint_t), &(*cache)[unicode]); } *glyph = (*cache)[unicode];
diff --git a/ui/gfx/image/image_skia_operations.cc b/ui/gfx/image/image_skia_operations.cc index f4940be..4f23d5601 100644 --- a/ui/gfx/image/image_skia_operations.cc +++ b/ui/gfx/image/image_skia_operations.cc
@@ -409,9 +409,9 @@ // CanvasImageSource overrides: void Draw(Canvas* canvas) override { - cc::PaintFlags paint; - paint.setLooper(CreateShadowDrawLooperCorrectBlur(shadows_)); - canvas->DrawRect(RectF(0, fades_down_ ? -1 : size().height(), 1, 1), paint); + cc::PaintFlags flags; + flags.setLooper(CreateShadowDrawLooperCorrectBlur(shadows_)); + canvas->DrawRect(RectF(0, fades_down_ ? -1 : size().height(), 1, 1), flags); } private:
diff --git a/ui/gfx/nine_image_painter.cc b/ui/gfx/nine_image_painter.cc index 60c8d021..fa1afe44 100644 --- a/ui/gfx/nine_image_painter.cc +++ b/ui/gfx/nine_image_painter.cc
@@ -43,10 +43,10 @@ int y, int w, int h, - const cc::PaintFlags& paint) { + const cc::PaintFlags& flags) { if (rep.is_null()) return; - c->DrawImageIntInPixel(rep, x, y, w, h, false, paint); + c->DrawImageIntInPixel(rep, x, y, w, h, false, flags); } } // namespace @@ -157,21 +157,21 @@ int i4h = std::max(height_in_pixels - i4y - std::min(std::min(i6h, i7h), i8h), 0); - cc::PaintFlags paint; - paint.setAlpha(alpha); + cc::PaintFlags flags; + flags.setAlpha(alpha); - Fill(canvas, image_reps[4], i4x, i4y, i4w, i4h, paint); - Fill(canvas, image_reps[0], 0, 0, i0w, i0h, paint); - Fill(canvas, image_reps[1], i0w, 0, width_in_pixels - i0w - i2w, i1h, paint); - Fill(canvas, image_reps[2], width_in_pixels - i2w, 0, i2w, i2h, paint); - Fill(canvas, image_reps[3], 0, i0h, i3w, height_in_pixels - i0h - i6h, paint); + Fill(canvas, image_reps[4], i4x, i4y, i4w, i4h, flags); + Fill(canvas, image_reps[0], 0, 0, i0w, i0h, flags); + Fill(canvas, image_reps[1], i0w, 0, width_in_pixels - i0w - i2w, i1h, flags); + Fill(canvas, image_reps[2], width_in_pixels - i2w, 0, i2w, i2h, flags); + Fill(canvas, image_reps[3], 0, i0h, i3w, height_in_pixels - i0h - i6h, flags); Fill(canvas, image_reps[5], width_in_pixels - i5w, i2h, i5w, - height_in_pixels - i2h - i8h, paint); - Fill(canvas, image_reps[6], 0, height_in_pixels - i6h, i6w, i6h, paint); + height_in_pixels - i2h - i8h, flags); + Fill(canvas, image_reps[6], 0, height_in_pixels - i6h, i6w, i6h, flags); Fill(canvas, image_reps[7], i6w, height_in_pixels - i7h, - width_in_pixels - i6w - i8w, i7h, paint); + width_in_pixels - i6w - i8w, i7h, flags); Fill(canvas, image_reps[8], width_in_pixels - i8w, height_in_pixels - i8h, - i8w, i8h, paint); + i8w, i8h, flags); } // static
diff --git a/ui/gfx/paint_throbber.cc b/ui/gfx/paint_throbber.cc index 2580687..f3486a6 100644 --- a/ui/gfx/paint_throbber.cc +++ b/ui/gfx/paint_throbber.cc
@@ -47,13 +47,13 @@ SkPath path; path.arcTo(RectToSkRect(oval), start_angle, sweep, true); - cc::PaintFlags paint; - paint.setColor(color); - paint.setStrokeCap(cc::PaintFlags::kRound_Cap); - paint.setStrokeWidth(stroke_width); - paint.setStyle(cc::PaintFlags::kStroke_Style); - paint.setAntiAlias(true); - canvas->DrawPath(path, paint); + cc::PaintFlags flags; + flags.setColor(color); + flags.setStrokeCap(cc::PaintFlags::kRound_Cap); + flags.setStrokeWidth(stroke_width); + flags.setStyle(cc::PaintFlags::kStroke_Style); + flags.setAntiAlias(true); + canvas->DrawPath(path, flags); } void CalculateWaitingAngles(const base::TimeDelta& elapsed_time,
diff --git a/ui/gfx/paint_vector_icon.cc b/ui/gfx/paint_vector_icon.cc index 3a9fdd4..7d1601dc 100644 --- a/ui/gfx/paint_vector_icon.cc +++ b/ui/gfx/paint_vector_icon.cc
@@ -90,7 +90,7 @@ int canvas_size = kReferenceSizeDip; std::vector<SkPath> paths; - std::vector<cc::PaintFlags> paints; + std::vector<cc::PaintFlags> flags_array; SkRect clip_rect = SkRect::MakeEmpty(); bool flips_in_rtl = false; CommandType previous_command_type = NEW_PATH; @@ -100,14 +100,14 @@ paths.push_back(SkPath()); paths.back().setFillType(SkPath::kEvenOdd_FillType); - paints.push_back(cc::PaintFlags()); - paints.back().setColor(color); - paints.back().setAntiAlias(true); - paints.back().setStrokeCap(cc::PaintFlags::kRound_Cap); + flags_array.push_back(cc::PaintFlags()); + flags_array.back().setColor(color); + flags_array.back().setAntiAlias(true); + flags_array.back().setStrokeCap(cc::PaintFlags::kRound_Cap); } SkPath& path = paths.back(); - cc::PaintFlags& paint = paints.back(); + cc::PaintFlags& flags = flags_array.back(); CommandType command_type = path_elements[i].type; switch (command_type) { // Handled above. @@ -119,24 +119,24 @@ int r = SkScalarFloorToInt(path_elements[++i].arg); int g = SkScalarFloorToInt(path_elements[++i].arg); int b = SkScalarFloorToInt(path_elements[++i].arg); - paint.setColor(SkColorSetARGB(a, r, g, b)); + flags.setColor(SkColorSetARGB(a, r, g, b)); break; } case PATH_MODE_CLEAR: { - paint.setBlendMode(SkBlendMode::kClear); + flags.setBlendMode(SkBlendMode::kClear); break; }; case STROKE: { - paint.setStyle(cc::PaintFlags::kStroke_Style); + flags.setStyle(cc::PaintFlags::kStroke_Style); SkScalar width = path_elements[++i].arg; - paint.setStrokeWidth(width); + flags.setStrokeWidth(width); break; } case CAP_SQUARE: { - paint.setStrokeCap(cc::PaintFlags::kSquare_Cap); + flags.setStrokeCap(cc::PaintFlags::kSquare_Cap); break; } @@ -310,7 +310,7 @@ } case DISABLE_AA: { - paint.setAntiAlias(false); + flags.setAntiAlias(false); break; } @@ -338,9 +338,9 @@ if (!clip_rect.isEmpty()) canvas->sk_canvas()->clipRect(clip_rect); - DCHECK_EQ(paints.size(), paths.size()); + DCHECK_EQ(flags_array.size(), paths.size()); for (size_t i = 0; i < paths.size(); ++i) - canvas->DrawPath(paths[i], paints[i]); + canvas->DrawPath(paths[i], flags_array[i]); } class VectorIconSource : public CanvasImageSource {
diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc index 69c7c0b..629fb60 100644 --- a/ui/gfx/render_text.cc +++ b/ui/gfx/render_text.cc
@@ -223,44 +223,44 @@ underline_thickness_(kUnderlineMetricsNotSet), underline_position_(0.0f) { DCHECK(canvas_skia_); - paint_.setTextEncoding(cc::PaintFlags::kGlyphID_TextEncoding); - paint_.setStyle(cc::PaintFlags::kFill_Style); - paint_.setAntiAlias(true); - paint_.setSubpixelText(true); - paint_.setLCDRenderText(true); - paint_.setHinting(cc::PaintFlags::kNormal_Hinting); + flags_.setTextEncoding(cc::PaintFlags::kGlyphID_TextEncoding); + flags_.setStyle(cc::PaintFlags::kFill_Style); + flags_.setAntiAlias(true); + flags_.setSubpixelText(true); + flags_.setLCDRenderText(true); + flags_.setHinting(cc::PaintFlags::kNormal_Hinting); } SkiaTextRenderer::~SkiaTextRenderer() { } void SkiaTextRenderer::SetDrawLooper(sk_sp<SkDrawLooper> draw_looper) { - paint_.setLooper(std::move(draw_looper)); + flags_.setLooper(std::move(draw_looper)); } void SkiaTextRenderer::SetFontRenderParams(const FontRenderParams& params, bool subpixel_rendering_suppressed) { - ApplyRenderParams(params, subpixel_rendering_suppressed, &paint_); + ApplyRenderParams(params, subpixel_rendering_suppressed, &flags_); } void SkiaTextRenderer::SetTypeface(sk_sp<SkTypeface> typeface) { - paint_.setTypeface(std::move(typeface)); + flags_.setTypeface(std::move(typeface)); } void SkiaTextRenderer::SetTextSize(SkScalar size) { - paint_.setTextSize(size); + flags_.setTextSize(size); } void SkiaTextRenderer::SetForegroundColor(SkColor foreground) { - paint_.setColor(foreground); + flags_.setColor(foreground); } void SkiaTextRenderer::SetShader(sk_sp<SkShader> shader) { - paint_.setShader(cc::WrapSkShader(std::move(shader))); + flags_.setShader(cc::WrapSkShader(std::move(shader))); } void SkiaTextRenderer::SetHaloEffect() { - paint_.setImageFilter(SkDilateImageFilter::Make(1, 1, nullptr)); + flags_.setImageFilter(SkDilateImageFilter::Make(1, 1, nullptr)); } void SkiaTextRenderer::SetUnderlineMetrics(SkScalar thickness, @@ -273,7 +273,7 @@ const uint16_t* glyphs, size_t glyph_count) { const size_t byte_length = glyph_count * sizeof(glyphs[0]); - canvas_skia_->drawPosText(&glyphs[0], byte_length, &pos[0], paint_); + canvas_skia_->drawPosText(&glyphs[0], byte_length, &pos[0], flags_); } void SkiaTextRenderer::DrawDecorations(int x, int y, int width, bool underline, @@ -284,8 +284,8 @@ DrawStrike(x, y, width); if (diagonal_strike) { if (!diagonal_) - diagonal_.reset(new DiagonalStrike(canvas_, Point(x, y), paint_)); - diagonal_->AddPiece(width, paint_.getColor()); + diagonal_.reset(new DiagonalStrike(canvas_, Point(x, y), flags_)); + diagonal_->AddPiece(width, flags_.getColor()); } else if (diagonal_) { EndDiagonalStrike(); } @@ -304,27 +304,27 @@ x_scalar, y + underline_position_, x_scalar + width, y + underline_position_ + underline_thickness_); if (underline_thickness_ == kUnderlineMetricsNotSet) { - const SkScalar text_size = paint_.getTextSize(); + const SkScalar text_size = flags_.getTextSize(); r.fTop = SkScalarMulAdd(text_size, kUnderlineOffset, y); r.fBottom = r.fTop + SkScalarMul(text_size, kLineThickness); } - canvas_skia_->drawRect(r, paint_); + canvas_skia_->drawRect(r, flags_); } void SkiaTextRenderer::DrawStrike(int x, int y, int width) const { - const SkScalar text_size = paint_.getTextSize(); + const SkScalar text_size = flags_.getTextSize(); const SkScalar height = SkScalarMul(text_size, kLineThickness); const SkScalar offset = SkScalarMulAdd(text_size, kStrikeThroughOffset, y); SkScalar x_scalar = SkIntToScalar(x); const SkRect r = SkRect::MakeLTRB(x_scalar, offset, x_scalar + width, offset + height); - canvas_skia_->drawRect(r, paint_); + canvas_skia_->drawRect(r, flags_); } SkiaTextRenderer::DiagonalStrike::DiagonalStrike(Canvas* canvas, Point start, - const cc::PaintFlags& paint) - : canvas_(canvas), start_(start), paint_(paint), total_length_(0) {} + const cc::PaintFlags& flags) + : canvas_(canvas), start_(start), flags_(flags), total_length_(0) {} SkiaTextRenderer::DiagonalStrike::~DiagonalStrike() { } @@ -335,7 +335,7 @@ } void SkiaTextRenderer::DiagonalStrike::Draw() { - const SkScalar text_size = paint_.getTextSize(); + const SkScalar text_size = flags_.getTextSize(); const SkScalar offset = SkScalarMul(text_size, kDiagonalStrikeMarginOffset); const int thickness = SkScalarCeilToInt(SkScalarMul(text_size, kLineThickness) * 2); @@ -343,14 +343,14 @@ const Point end = start_ + Vector2d(total_length_, -height); const int clip_height = height + 2 * thickness; - paint_.setAntiAlias(true); - paint_.setStrokeWidth(SkIntToScalar(thickness)); + flags_.setAntiAlias(true); + flags_.setStrokeWidth(SkIntToScalar(thickness)); const bool clipped = pieces_.size() > 1; int x = start_.x(); for (size_t i = 0; i < pieces_.size(); ++i) { - paint_.setColor(pieces_[i].second); + flags_.setColor(pieces_[i].second); if (clipped) { canvas_->Save(); @@ -358,7 +358,7 @@ Rect(x, end.y() - thickness, pieces_[i].first, clip_height)); } - canvas_->DrawLine(start_, end, paint_); + canvas_->DrawLine(start_, end, flags_); if (clipped) canvas_->Restore(); @@ -413,13 +413,14 @@ void ApplyRenderParams(const FontRenderParams& params, bool subpixel_rendering_suppressed, - cc::PaintFlags* paint) { - paint->setAntiAlias(params.antialiasing); - paint->setLCDRenderText(!subpixel_rendering_suppressed && - params.subpixel_rendering != FontRenderParams::SUBPIXEL_RENDERING_NONE); - paint->setSubpixelText(params.subpixel_positioning); - paint->setAutohinted(params.autohinter); - paint->setHinting(FontRenderParamsHintingToPaintFlagsHinting(params.hinting)); + cc::PaintFlags* flags) { + flags->setAntiAlias(params.antialiasing); + flags->setLCDRenderText(!subpixel_rendering_suppressed && + params.subpixel_rendering != + FontRenderParams::SUBPIXEL_RENDERING_NONE); + flags->setSubpixelText(params.subpixel_positioning); + flags->setAutohinted(params.autohinter); + flags->setHinting(FontRenderParamsHintingToPaintFlagsHinting(params.hinting)); } } // namespace internal
diff --git a/ui/gfx/render_text.h b/ui/gfx/render_text.h index 7a1b828..5feb6a2 100644 --- a/ui/gfx/render_text.h +++ b/ui/gfx/render_text.h
@@ -90,7 +90,7 @@ // lengths and colors; to support text selection appearances. class DiagonalStrike { public: - DiagonalStrike(Canvas* canvas, Point start, const cc::PaintFlags& paint); + DiagonalStrike(Canvas* canvas, Point start, const cc::PaintFlags& flags); ~DiagonalStrike(); void AddPiece(int length, SkColor color); @@ -101,7 +101,7 @@ Canvas* canvas_; const Point start_; - cc::PaintFlags paint_; + cc::PaintFlags flags_; int total_length_; std::vector<Piece> pieces_; @@ -110,7 +110,7 @@ Canvas* canvas_; cc::PaintCanvas* canvas_skia_; - cc::PaintFlags paint_; + cc::PaintFlags flags_; SkScalar underline_thickness_; SkScalar underline_position_; std::unique_ptr<DiagonalStrike> diagonal_; @@ -196,10 +196,10 @@ bool italic, Font::Weight weight); -// Applies the given FontRenderParams to a Skia |paint|. +// Applies the given FontRenderParams to the PaintFlags. void ApplyRenderParams(const FontRenderParams& params, bool subpixel_rendering_suppressed, - cc::PaintFlags* paint); + cc::PaintFlags* flags); } // namespace internal
diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc index 7002801..6c98376f 100644 --- a/ui/gfx/render_text_unittest.cc +++ b/ui/gfx/render_text_unittest.cc
@@ -62,8 +62,9 @@ public: RenderTextTestApi(RenderText* render_text) : render_text_(render_text) {} - static SkPaint& GetRendererPaint(internal::SkiaTextRenderer* renderer) { - return renderer->paint_; + static cc::PaintFlags& GetRendererPaint( + internal::SkiaTextRenderer* renderer) { + return renderer->flags_; } // Callers should ensure that the associated RenderText object is a @@ -443,7 +444,7 @@ return nullptr; } - SkPaint& GetRendererPaint() { + cc::PaintFlags& GetRendererPaint() { return test::RenderTextTestApi::GetRendererPaint(renderer()); }
diff --git a/ui/gfx/vector_icons/BUILD.gn b/ui/gfx/vector_icons/BUILD.gn index 0f5abcf0..c737b8c5 100644 --- a/ui/gfx/vector_icons/BUILD.gn +++ b/ui/gfx/vector_icons/BUILD.gn
@@ -15,8 +15,6 @@ "account_child_circle.icon", "account_circle.icon", "apps.icon", - "bar_close.1x.icon", - "bar_close.icon", "blocked_badge.icon", "business.icon", "check_circle.1x.icon",
diff --git a/ui/gl/gl_bindings.h b/ui/gl/gl_bindings.h index 3ea6199..34ec554 100644 --- a/ui/gl/gl_bindings.h +++ b/ui/gl/gl_bindings.h
@@ -135,9 +135,6 @@ // GL_CHROMIUM_sync_query #define GL_COMMANDS_COMPLETED_CHROMIUM 0x84F7 -// GL_CHROMIUM_gpu_memory_buffer_image -#define GL_READ_WRITE_CHROMIUM 0x78F2 - // GL_CHROMIUM_ycrcb_420_image #define GL_RGB_YCRCB_420_CHROMIUM 0x78FA
diff --git a/ui/login/account_picker/user_pod_row.js b/ui/login/account_picker/user_pod_row.js index cf09257..24e6885 100644 --- a/ui/login/account_picker/user_pod_row.js +++ b/ui/login/account_picker/user_pod_row.js
@@ -3347,6 +3347,8 @@ this.firstShown_ = false; this.lastFocusedPod_ = podToFocus; this.scrollFocusedPodIntoView(); + } else { + chrome.send('noPodFocused'); } this.insideFocusPod_ = false; },
diff --git a/ui/login/oobe.css b/ui/login/oobe.css index 0309ec0..a21b12e 100644 --- a/ui/login/oobe.css +++ b/ui/login/oobe.css
@@ -147,11 +147,13 @@ color: #fff; font-size: 11px; margin: 10px; + position: relative; text-align: end; text-shadow: 0 0 4px rgba(0,0,0,.6), 0 1px 2px rgba(0,0,0,.8), 0 -1px 2px rgba(0,0,0,1); + z-index: 1; } #background {
diff --git a/ui/native_theme/common_theme.cc b/ui/native_theme/common_theme.cc index 861e4e19..021abe1f 100644 --- a/ui/native_theme/common_theme.cc +++ b/ui/native_theme/common_theme.cc
@@ -344,15 +344,15 @@ NativeTheme::State state, const gfx::Rect& rect, const NativeTheme::MenuItemExtraParams& menu_item) { - cc::PaintFlags paint; + cc::PaintFlags flags; switch (state) { case NativeTheme::kNormal: case NativeTheme::kDisabled: - paint.setColor( + flags.setColor( theme->GetSystemColor(NativeTheme::kColorId_MenuBackgroundColor)); break; case NativeTheme::kHovered: - paint.setColor(theme->GetSystemColor( + flags.setColor(theme->GetSystemColor( NativeTheme::kColorId_FocusedMenuItemBackgroundColor)); break; default: @@ -361,10 +361,10 @@ } if (menu_item.corner_radius > 0) { const SkScalar radius = SkIntToScalar(menu_item.corner_radius); - canvas->drawRoundRect(gfx::RectToSkRect(rect), radius, radius, paint); + canvas->drawRoundRect(gfx::RectToSkRect(rect), radius, radius, flags); return; } - canvas->drawRect(gfx::RectToSkRect(rect), paint); + canvas->drawRect(gfx::RectToSkRect(rect), flags); } } // namespace ui
diff --git a/ui/native_theme/native_theme_aura.cc b/ui/native_theme/native_theme_aura.cc index 94fb36a..0c3255cb 100644 --- a/ui/native_theme/native_theme_aura.cc +++ b/ui/native_theme/native_theme_aura.cc
@@ -102,10 +102,10 @@ const MenuBackgroundExtraParams& menu_background) const { SkColor color = GetSystemColor(NativeTheme::kColorId_MenuBackgroundColor); if (menu_background.corner_radius > 0) { - cc::PaintFlags paint; - paint.setStyle(cc::PaintFlags::kFill_Style); - paint.setAntiAlias(true); - paint.setColor(color); + cc::PaintFlags flags; + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setAntiAlias(true); + flags.setColor(color); gfx::Path path; SkRect rect = SkRect::MakeWH(SkIntToScalar(size.width()), @@ -115,7 +115,7 @@ radius, radius, radius, radius}; path.addRoundRect(rect, radii); - canvas->drawPath(path, paint); + canvas->drawPath(path, flags); } else { canvas->drawColor(color, SkBlendMode::kSrc); } @@ -155,9 +155,9 @@ } DCHECK_NE(arrow_color, gfx::kPlaceholderColor); - cc::PaintFlags paint; - paint.setColor(bg_color); - canvas->drawIRect(gfx::RectToSkIRect(rect), paint); + cc::PaintFlags flags; + flags.setColor(bg_color); + canvas->drawIRect(gfx::RectToSkIRect(rect), flags); PaintArrow(canvas, rect, direction, arrow_color); } @@ -170,9 +170,9 @@ const gfx::Rect& rect) const { // Overlay Scrollbar should never paint a scrollbar track. DCHECK(!use_overlay_scrollbars_); - cc::PaintFlags paint; - paint.setColor(kTrackColor); - canvas->drawIRect(gfx::RectToSkIRect(rect), paint); + cc::PaintFlags flags; + flags.setColor(kTrackColor); + canvas->drawIRect(gfx::RectToSkIRect(rect), flags); } void NativeThemeAura::PaintScrollbarThumb( @@ -233,16 +233,16 @@ // In overlay mode, draw a stroke (border). constexpr int kStrokeWidth = kOverlayScrollbarStrokeWidth; - cc::PaintFlags paint; - paint.setColor( + cc::PaintFlags flags; + flags.setColor( SkColorSetA(kOverlayScrollbarStrokeColor[theme], stroke_alpha)); - paint.setStyle(cc::PaintFlags::kStroke_Style); - paint.setStrokeWidth(kStrokeWidth); + flags.setStyle(cc::PaintFlags::kStroke_Style); + flags.setStrokeWidth(kStrokeWidth); gfx::RectF stroke_rect(thumb_rect); constexpr float kHalfStrokeWidth = kStrokeWidth / 2.f; stroke_rect.Inset(kHalfStrokeWidth, kHalfStrokeWidth); - canvas->drawRect(gfx::RectFToSkRect(stroke_rect), paint); + canvas->drawRect(gfx::RectFToSkRect(stroke_rect), flags); // Inset the all the edges edges so we fill-in the stroke below. thumb_rect.Inset(kStrokeWidth, kStrokeWidth); @@ -277,9 +277,9 @@ thumb_color = SK_ColorBLACK; } - cc::PaintFlags paint; - paint.setColor(SkColorSetA(thumb_color, thumb_alpha)); - canvas->drawIRect(gfx::RectToSkIRect(thumb_rect), paint); + cc::PaintFlags flags; + flags.setColor(SkColorSetA(thumb_color, thumb_alpha)); + canvas->drawIRect(gfx::RectToSkIRect(thumb_rect), flags); } void NativeThemeAura::PaintScrollbarCorner(cc::PaintCanvas* canvas, @@ -287,9 +287,9 @@ const gfx::Rect& rect) const { // Overlay Scrollbar should never paint a scrollbar corner. DCHECK(!use_overlay_scrollbars_); - cc::PaintFlags paint; - paint.setColor(SkColorSetRGB(0xDC, 0xDC, 0xDC)); - canvas->drawIRect(RectToSkIRect(rect), paint); + cc::PaintFlags flags; + flags.setColor(SkColorSetRGB(0xDC, 0xDC, 0xDC)); + canvas->drawIRect(RectToSkIRect(rect), flags); } gfx::Size NativeThemeAura::GetPartSize(Part part,
diff --git a/ui/native_theme/native_theme_base.cc b/ui/native_theme/native_theme_base.cc index 438d0f1..596cf04 100644 --- a/ui/native_theme/native_theme_base.cc +++ b/ui/native_theme/native_theme_base.cc
@@ -263,7 +263,7 @@ const gfx::Rect& rect, Part direction, State state) const { - cc::PaintFlags paint; + cc::PaintFlags flags; // Calculate button color. SkScalar trackHSV[3]; @@ -284,8 +284,8 @@ skrect.set(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height()); // Paint the background (the area visible behind the rounded corners). - paint.setColor(backgroundColor); - canvas->drawIRect(skrect, paint); + flags.setColor(backgroundColor); + canvas->drawIRect(skrect, flags); // Paint the button's outline and fill the middle SkPath outline; @@ -327,16 +327,16 @@ } outline.close(); - paint.setStyle(cc::PaintFlags::kFill_Style); - paint.setColor(buttonColor); - canvas->drawPath(outline, paint); + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setColor(buttonColor); + canvas->drawPath(outline, flags); - paint.setAntiAlias(true); - paint.setStyle(cc::PaintFlags::kStroke_Style); + flags.setAntiAlias(true); + flags.setStyle(cc::PaintFlags::kStroke_Style); SkScalar thumbHSV[3]; SkColorToHSV(thumb_inactive_color_, thumbHSV); - paint.setColor(OutlineColor(trackHSV, thumbHSV)); - canvas->drawPath(outline, paint); + flags.setColor(OutlineColor(trackHSV, thumbHSV)); + canvas->drawPath(outline, flags); PaintArrow(canvas, rect, direction, GetArrowColor(state)); } @@ -345,12 +345,12 @@ const gfx::Rect& rect, Part direction, SkColor color) const { - cc::PaintFlags paint; - paint.setColor(color); + cc::PaintFlags flags; + flags.setColor(color); SkPath path = PathForArrow(rect, direction); - gc->drawPath(path, paint); + gc->drawPath(path, flags); } SkPath NativeThemeBase::PathForArrow(const gfx::Rect& rect, @@ -404,20 +404,20 @@ State state, const ScrollbarTrackExtraParams& extra_params, const gfx::Rect& rect) const { - cc::PaintFlags paint; + cc::PaintFlags flags; SkIRect skrect; skrect.set(rect.x(), rect.y(), rect.right(), rect.bottom()); SkScalar track_hsv[3]; SkColorToHSV(track_color_, track_hsv); - paint.setColor(SaturateAndBrighten(track_hsv, 0, 0)); - canvas->drawIRect(skrect, paint); + flags.setColor(SaturateAndBrighten(track_hsv, 0, 0)); + canvas->drawIRect(skrect, flags); SkScalar thumb_hsv[3]; SkColorToHSV(thumb_inactive_color_, thumb_hsv); - paint.setColor(OutlineColor(track_hsv, thumb_hsv)); - DrawBox(canvas, rect, paint); + flags.setColor(OutlineColor(track_hsv, thumb_hsv)); + DrawBox(canvas, rect, flags); } void NativeThemeBase::PaintScrollbarThumb(cc::PaintCanvas* canvas, @@ -433,8 +433,8 @@ SkScalar thumb[3]; SkColorToHSV(hovered ? thumb_active_color_ : thumb_inactive_color_, thumb); - cc::PaintFlags paint; - paint.setColor(SaturateAndBrighten(thumb, 0, 0.02f)); + cc::PaintFlags flags; + flags.setColor(SaturateAndBrighten(thumb, 0, 0.02f)); SkIRect skrect; if (vertical) @@ -442,9 +442,9 @@ else skrect.set(rect.x(), rect.y(), rect.x() + rect.width(), midy + 1); - canvas->drawIRect(skrect, paint); + canvas->drawIRect(skrect, flags); - paint.setColor(SaturateAndBrighten(thumb, 0, -0.02f)); + flags.setColor(SaturateAndBrighten(thumb, 0, -0.02f)); if (vertical) { skrect.set( @@ -454,48 +454,30 @@ rect.x(), midy + 1, rect.x() + rect.width(), rect.y() + rect.height()); } - canvas->drawIRect(skrect, paint); + canvas->drawIRect(skrect, flags); SkScalar track[3]; SkColorToHSV(track_color_, track); - paint.setColor(OutlineColor(track, thumb)); - DrawBox(canvas, rect, paint); + flags.setColor(OutlineColor(track, thumb)); + DrawBox(canvas, rect, flags); if (rect.height() > 10 && rect.width() > 10) { const int grippy_half_width = 2; const int inter_grippy_offset = 3; if (vertical) { - DrawHorizLine(canvas, - midx - grippy_half_width, - midx + grippy_half_width, - midy - inter_grippy_offset, - paint); - DrawHorizLine(canvas, - midx - grippy_half_width, - midx + grippy_half_width, - midy, - paint); - DrawHorizLine(canvas, - midx - grippy_half_width, - midx + grippy_half_width, - midy + inter_grippy_offset, - paint); + DrawHorizLine(canvas, midx - grippy_half_width, midx + grippy_half_width, + midy - inter_grippy_offset, flags); + DrawHorizLine(canvas, midx - grippy_half_width, midx + grippy_half_width, + midy, flags); + DrawHorizLine(canvas, midx - grippy_half_width, midx + grippy_half_width, + midy + inter_grippy_offset, flags); } else { - DrawVertLine(canvas, - midx - inter_grippy_offset, - midy - grippy_half_width, - midy + grippy_half_width, - paint); - DrawVertLine(canvas, - midx, - midy - grippy_half_width, - midy + grippy_half_width, - paint); - DrawVertLine(canvas, - midx + inter_grippy_offset, - midy - grippy_half_width, - midy + grippy_half_width, - paint); + DrawVertLine(canvas, midx - inter_grippy_offset, midy - grippy_half_width, + midy + grippy_half_width, flags); + DrawVertLine(canvas, midx, midy - grippy_half_width, + midy + grippy_half_width, flags); + DrawVertLine(canvas, midx + inter_grippy_offset, midy - grippy_half_width, + midy + grippy_half_width, flags); } } } @@ -512,29 +494,29 @@ SkIntToScalar(2)); if (!skrect.isEmpty()) { // Draw the checkmark / dash. - cc::PaintFlags paint; - paint.setAntiAlias(true); - paint.setStyle(cc::PaintFlags::kStroke_Style); + cc::PaintFlags flags; + flags.setAntiAlias(true); + flags.setStyle(cc::PaintFlags::kStroke_Style); if (state == kDisabled) - paint.setColor(kCheckboxStrokeDisabledColor); + flags.setColor(kCheckboxStrokeDisabledColor); else - paint.setColor(kCheckboxStrokeColor); + flags.setColor(kCheckboxStrokeColor); if (button.indeterminate) { SkPath dash; dash.moveTo(skrect.x() + skrect.width() * 0.16, (skrect.y() + skrect.bottom()) / 2); dash.rLineTo(skrect.width() * 0.68, 0); - paint.setStrokeWidth(SkFloatToScalar(skrect.height() * 0.2)); - canvas->drawPath(dash, paint); + flags.setStrokeWidth(SkFloatToScalar(skrect.height() * 0.2)); + canvas->drawPath(dash, flags); } else if (button.checked) { SkPath check; check.moveTo(skrect.x() + skrect.width() * 0.2, skrect.y() + skrect.height() * 0.5); check.rLineTo(skrect.width() * 0.2, skrect.height() * 0.2); - paint.setStrokeWidth(SkFloatToScalar(skrect.height() * 0.23)); + flags.setStrokeWidth(SkFloatToScalar(skrect.height() * 0.23)); check.lineTo(skrect.right() - skrect.width() * 0.2, skrect.y() + skrect.height() * 0.2); - canvas->drawPath(check, paint); + canvas->drawPath(check, flags); } } } @@ -561,10 +543,10 @@ // to have to worry about '- 1' and '+ 1' calculations below having overflow // or underflow. if (skrect.width() <= 2) { - cc::PaintFlags paint; - paint.setColor(kCheckboxTinyColor); - paint.setStyle(cc::PaintFlags::kFill_Style); - canvas->drawRect(skrect, paint); + cc::PaintFlags flags; + flags.setColor(kCheckboxTinyColor); + flags.setStyle(cc::PaintFlags::kFill_Style); + canvas->drawRect(skrect, flags); // Too small to draw anything more. return SkRect::MakeEmpty(); } @@ -574,18 +556,18 @@ // Draw the drop shadow below the widget. if (state != kPressed) { - cc::PaintFlags paint; - paint.setAntiAlias(true); + cc::PaintFlags flags; + flags.setAntiAlias(true); SkRect shadowRect = skrect; shadowRect.offset(0, 1); if (state == kDisabled) - paint.setColor(kCheckboxShadowDisabledColor); + flags.setColor(kCheckboxShadowDisabledColor); else if (state == kHovered) - paint.setColor(kCheckboxShadowHoveredColor); + flags.setColor(kCheckboxShadowHoveredColor); else - paint.setColor(kCheckboxShadowColor); - paint.setStyle(cc::PaintFlags::kFill_Style); - canvas->drawRoundRect(shadowRect, borderRadius, borderRadius, paint); + flags.setColor(kCheckboxShadowColor); + flags.setStyle(cc::PaintFlags::kFill_Style); + canvas->drawRoundRect(shadowRect, borderRadius, borderRadius, flags); } // Draw the gradient-filled rectangle @@ -603,25 +585,25 @@ else /* kNormal */ startEndColors = kCheckboxGradientColors; SkColor colors[3] = {startEndColors[0], startEndColors[0], startEndColors[1]}; - cc::PaintFlags paint; - paint.setAntiAlias(true); - paint.setShader(cc::WrapSkShader(SkGradientShader::MakeLinear( + cc::PaintFlags flags; + flags.setAntiAlias(true); + flags.setShader(cc::WrapSkShader(SkGradientShader::MakeLinear( gradient_bounds, colors, NULL, 3, SkShader::kClamp_TileMode))); - paint.setStyle(cc::PaintFlags::kFill_Style); - canvas->drawRoundRect(skrect, borderRadius, borderRadius, paint); - paint.setShader(NULL); + flags.setStyle(cc::PaintFlags::kFill_Style); + canvas->drawRoundRect(skrect, borderRadius, borderRadius, flags); + flags.setShader(NULL); // Draw the border. if (state == kHovered) - paint.setColor(kCheckboxBorderHoveredColor); + flags.setColor(kCheckboxBorderHoveredColor); else if (state == kDisabled) - paint.setColor(kCheckboxBorderDisabledColor); + flags.setColor(kCheckboxBorderDisabledColor); else - paint.setColor(kCheckboxBorderColor); - paint.setStyle(cc::PaintFlags::kStroke_Style); - paint.setStrokeWidth(SkIntToScalar(1)); + flags.setColor(kCheckboxBorderColor); + flags.setStyle(cc::PaintFlags::kStroke_Style); + flags.setStrokeWidth(SkIntToScalar(1)); skrect.inset(SkFloatToScalar(.5f), SkFloatToScalar(.5f)); - canvas->drawRoundRect(skrect, borderRadius, borderRadius, paint); + canvas->drawRoundRect(skrect, borderRadius, borderRadius, flags); // Return the rectangle excluding the drop shadow for drawing any additional // decorations. @@ -639,17 +621,17 @@ SkRect skrect = PaintCheckboxRadioCommon(canvas, state, rect, radius); if (!skrect.isEmpty() && button.checked) { // Draw the dot. - cc::PaintFlags paint; - paint.setAntiAlias(true); - paint.setStyle(cc::PaintFlags::kFill_Style); + cc::PaintFlags flags; + flags.setAntiAlias(true); + flags.setStyle(cc::PaintFlags::kFill_Style); if (state == kDisabled) - paint.setColor(kRadioDotDisabledColor); + flags.setColor(kRadioDotDisabledColor); else - paint.setColor(kRadioDotColor); + flags.setColor(kRadioDotColor); skrect.inset(skrect.width() * 0.25, skrect.height() * 0.25); // Use drawRoundedRect instead of drawOval to be completely consistent // with the border in PaintCheckboxRadioNewCommon. - canvas->drawRoundRect(skrect, radius, radius, paint); + canvas->drawRoundRect(skrect, radius, radius, flags); } } @@ -657,7 +639,7 @@ State state, const gfx::Rect& rect, const ButtonExtraParams& button) const { - cc::PaintFlags paint; + cc::PaintFlags flags; SkRect skrect = gfx::RectToSkRect(rect); SkColor base_color = button.background_color; @@ -670,12 +652,12 @@ // If the button is too small, fallback to drawing a single, solid color if (rect.width() < 5 || rect.height() < 5) { - paint.setColor(base_color); - canvas->drawRect(skrect, paint); + flags.setColor(base_color); + canvas->drawRect(skrect, flags); return; } - paint.setColor(SK_ColorBLACK); + flags.setColor(SK_ColorBLACK); SkPoint gradient_bounds[2] = { gfx::PointToSkPoint(rect.origin()), gfx::PointToSkPoint(rect.bottom_left() - gfx::Vector2d(0, 1)) @@ -684,25 +666,25 @@ std::swap(gradient_bounds[0], gradient_bounds[1]); SkColor colors[2] = { light_color, base_color }; - paint.setStyle(cc::PaintFlags::kFill_Style); - paint.setAntiAlias(true); - paint.setShader(cc::WrapSkShader(SkGradientShader::MakeLinear( + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setAntiAlias(true); + flags.setShader(cc::WrapSkShader(SkGradientShader::MakeLinear( gradient_bounds, colors, NULL, 2, SkShader::kClamp_TileMode))); - canvas->drawRoundRect(skrect, SkIntToScalar(1), SkIntToScalar(1), paint); - paint.setShader(NULL); + canvas->drawRoundRect(skrect, SkIntToScalar(1), SkIntToScalar(1), flags); + flags.setShader(NULL); if (button.has_border) { int border_alpha = state == kHovered ? 0x80 : 0x55; if (button.is_focused) { border_alpha = 0xff; - paint.setColor(GetSystemColor(kColorId_FocusedBorderColor)); + flags.setColor(GetSystemColor(kColorId_FocusedBorderColor)); } - paint.setStyle(cc::PaintFlags::kStroke_Style); - paint.setStrokeWidth(SkIntToScalar(1)); - paint.setAlpha(border_alpha); + flags.setStyle(cc::PaintFlags::kStroke_Style); + flags.setStrokeWidth(SkIntToScalar(1)); + flags.setAlpha(border_alpha); skrect.inset(SkFloatToScalar(.5f), SkFloatToScalar(.5f)); - canvas->drawRoundRect(skrect, SkIntToScalar(1), SkIntToScalar(1), paint); + canvas->drawRoundRect(skrect, SkIntToScalar(1), SkIntToScalar(1), flags); } } @@ -713,17 +695,17 @@ SkRect bounds; bounds.set(rect.x(), rect.y(), rect.right() - 1, rect.bottom() - 1); - cc::PaintFlags fill_paint; - fill_paint.setStyle(cc::PaintFlags::kFill_Style); - fill_paint.setColor(text.background_color); - canvas->drawRect(bounds, fill_paint); + cc::PaintFlags fill_flags; + fill_flags.setStyle(cc::PaintFlags::kFill_Style); + fill_flags.setColor(text.background_color); + canvas->drawRect(bounds, fill_flags); // Text INPUT, listbox SELECT, and TEXTAREA have consistent borders. // border: 1px solid #a9a9a9 - cc::PaintFlags stroke_paint; - stroke_paint.setStyle(cc::PaintFlags::kStroke_Style); - stroke_paint.setColor(kTextBorderColor); - canvas->drawRect(bounds, stroke_paint); + cc::PaintFlags stroke_flags; + stroke_flags.setStyle(cc::PaintFlags::kStroke_Style); + stroke_flags.setColor(kTextBorderColor); + canvas->drawRect(bounds, stroke_flags); } void NativeThemeBase::PaintMenuList( @@ -740,10 +722,10 @@ PaintButton(canvas, state, rect, button); } - cc::PaintFlags paint; - paint.setColor(menu_list.arrow_color); - paint.setAntiAlias(true); - paint.setStyle(cc::PaintFlags::kFill_Style); + cc::PaintFlags flags; + flags.setColor(menu_list.arrow_color); + flags.setAntiAlias(true); + flags.setStyle(cc::PaintFlags::kFill_Style); int arrow_size = menu_list.arrow_size; gfx::Rect arrow( @@ -760,7 +742,7 @@ path.lineTo(arrow.right(), arrow.y()); path.lineTo(arrow.x() + arrow.width() / 2, arrow.bottom()); path.close(); - canvas->drawPath(path, paint); + canvas->drawPath(path, flags); } void NativeThemeBase::PaintMenuPopupBackground( @@ -783,9 +765,9 @@ State state, const gfx::Rect& rect, const MenuSeparatorExtraParams& menu_separator) const { - cc::PaintFlags paint; - paint.setColor(GetSystemColor(ui::NativeTheme::kColorId_MenuSeparatorColor)); - canvas->drawRect(gfx::RectToSkRect(*menu_separator.paint_rect), paint); + cc::PaintFlags flags; + flags.setColor(GetSystemColor(ui::NativeTheme::kColorId_MenuSeparatorColor)); + canvas->drawRect(gfx::RectToSkRect(*menu_separator.paint_rect), flags); } void NativeThemeBase::PaintSliderTrack(cc::PaintCanvas* canvas, @@ -795,8 +777,8 @@ const int kMidX = rect.x() + rect.width() / 2; const int kMidY = rect.y() + rect.height() / 2; - cc::PaintFlags paint; - paint.setColor(kSliderTrackBackgroundColor); + cc::PaintFlags flags; + flags.setColor(kSliderTrackBackgroundColor); SkRect skrect; if (slider.vertical) { @@ -810,7 +792,7 @@ rect.right(), std::min(rect.bottom(), kMidY + 2)); } - canvas->drawRect(skrect, paint); + canvas->drawRect(skrect, flags); } void NativeThemeBase::PaintSliderThumb(cc::PaintCanvas* canvas, @@ -821,8 +803,8 @@ const int kMidX = rect.x() + rect.width() / 2; const int kMidY = rect.y() + rect.height() / 2; - cc::PaintFlags paint; - paint.setColor(hovered ? SK_ColorWHITE : kSliderThumbLightGrey); + cc::PaintFlags flags; + flags.setColor(hovered ? SK_ColorWHITE : kSliderThumbLightGrey); SkIRect skrect; if (slider.vertical) @@ -830,24 +812,24 @@ else skrect.set(rect.x(), rect.y(), rect.right(), kMidY + 1); - canvas->drawIRect(skrect, paint); + canvas->drawIRect(skrect, flags); - paint.setColor(hovered ? kSliderThumbLightGrey : kSliderThumbDarkGrey); + flags.setColor(hovered ? kSliderThumbLightGrey : kSliderThumbDarkGrey); if (slider.vertical) skrect.set(kMidX + 1, rect.y(), rect.right(), rect.bottom()); else skrect.set(rect.x(), kMidY + 1, rect.right(), rect.bottom()); - canvas->drawIRect(skrect, paint); + canvas->drawIRect(skrect, flags); - paint.setColor(kSliderThumbBorderDarkGrey); - DrawBox(canvas, rect, paint); + flags.setColor(kSliderThumbBorderDarkGrey); + DrawBox(canvas, rect, flags); if (rect.height() > 10 && rect.width() > 10) { - DrawHorizLine(canvas, kMidX - 2, kMidX + 2, kMidY, paint); - DrawHorizLine(canvas, kMidX - 2, kMidX + 2, kMidY - 3, paint); - DrawHorizLine(canvas, kMidX - 2, kMidX + 2, kMidY + 3, paint); + DrawHorizLine(canvas, kMidX - 2, kMidX + 2, kMidY, flags); + DrawHorizLine(canvas, kMidX - 2, kMidX + 2, kMidY - 3, flags); + DrawHorizLine(canvas, kMidX - 2, kMidX + 2, kMidY + 3, flags); } } @@ -894,26 +876,26 @@ path.moveTo(rect.x() + i * tick_spacing, rect.y()); path.rLineTo(0, rect.height()); } - cc::PaintFlags stroke_paint; - stroke_paint.setColor(kProgressTickColor); - stroke_paint.setStyle(cc::PaintFlags::kStroke_Style); - stroke_paint.setStrokeWidth(stroke_width); - canvas->drawPath(path, stroke_paint); + cc::PaintFlags stroke_flags; + stroke_flags.setColor(kProgressTickColor); + stroke_flags.setStyle(cc::PaintFlags::kStroke_Style); + stroke_flags.setStrokeWidth(stroke_width); + canvas->drawPath(path, stroke_flags); // Draw progress. gfx::Rect progress_rect(progress_bar.value_rect_x, progress_bar.value_rect_y, progress_bar.value_rect_width, progress_bar.value_rect_height); - cc::PaintFlags progress_paint; - progress_paint.setColor(kProgressValueColor); - progress_paint.setStyle(cc::PaintFlags::kFill_Style); - canvas->drawRect(gfx::RectToSkRect(progress_rect), progress_paint); + cc::PaintFlags progress_flags; + progress_flags.setColor(kProgressValueColor); + progress_flags.setStyle(cc::PaintFlags::kFill_Style); + canvas->drawRect(gfx::RectToSkRect(progress_rect), progress_flags); // Draw the border. gfx::RectF border_rect(rect); border_rect.Inset(stroke_width / 2.0f, stroke_width / 2.0f); - stroke_paint.setColor(kProgressBorderColor); - canvas->drawRect(gfx::RectFToSkRect(border_rect), stroke_paint); + stroke_flags.setColor(kProgressBorderColor); + canvas->drawRect(gfx::RectFToSkRect(border_rect), stroke_flags); } void NativeThemeBase::PaintFrameTopArea( @@ -921,9 +903,9 @@ State state, const gfx::Rect& rect, const FrameTopAreaExtraParams& frame_top_area) const { - SkPaint paint; - paint.setColor(frame_top_area.default_background_color); - canvas->drawRect(gfx::RectToSkRect(rect), paint); + SkPaint flags; + flags.setColor(frame_top_area.default_background_color); + canvas->drawRect(gfx::RectToSkRect(rect), flags); } void NativeThemeBase::AdjustCheckboxRadioRectForPadding(SkRect* rect) const { @@ -956,31 +938,31 @@ int x, int y1, int y2, - const cc::PaintFlags& paint) const { + const cc::PaintFlags& flags) const { SkIRect skrect; skrect.set(x, y1, x + 1, y2 + 1); - canvas->drawIRect(skrect, paint); + canvas->drawIRect(skrect, flags); } void NativeThemeBase::DrawHorizLine(cc::PaintCanvas* canvas, int x1, int x2, int y, - const cc::PaintFlags& paint) const { + const cc::PaintFlags& flags) const { SkIRect skrect; skrect.set(x1, y, x2 + 1, y + 1); - canvas->drawIRect(skrect, paint); + canvas->drawIRect(skrect, flags); } void NativeThemeBase::DrawBox(cc::PaintCanvas* canvas, const gfx::Rect& rect, - const cc::PaintFlags& paint) const { + const cc::PaintFlags& flags) const { const int right = rect.x() + rect.width() - 1; const int bottom = rect.y() + rect.height() - 1; - DrawHorizLine(canvas, rect.x(), right, rect.y(), paint); - DrawVertLine(canvas, right, rect.y(), bottom, paint); - DrawHorizLine(canvas, rect.x(), right, bottom, paint); - DrawVertLine(canvas, rect.x(), rect.y(), bottom, paint); + DrawHorizLine(canvas, rect.x(), right, rect.y(), flags); + DrawVertLine(canvas, right, rect.y(), bottom, flags); + DrawHorizLine(canvas, rect.x(), right, bottom, flags); + DrawVertLine(canvas, rect.x(), rect.y(), bottom, flags); } SkScalar NativeThemeBase::Clamp(SkScalar value,
diff --git a/ui/native_theme/native_theme_base.h b/ui/native_theme/native_theme_base.h index 0e4f233e..f2590023 100644 --- a/ui/native_theme/native_theme_base.h +++ b/ui/native_theme/native_theme_base.h
@@ -169,15 +169,15 @@ int x, int y1, int y2, - const cc::PaintFlags& paint) const; + const cc::PaintFlags& flags) const; void DrawHorizLine(cc::PaintCanvas* canvas, int x1, int x2, int y, - const cc::PaintFlags& paint) const; + const cc::PaintFlags& flags) const; void DrawBox(cc::PaintCanvas* canvas, const gfx::Rect& rect, - const cc::PaintFlags& paint) const; + const cc::PaintFlags& flags) const; SkScalar Clamp(SkScalar value, SkScalar min, SkScalar max) const;
diff --git a/ui/native_theme/native_theme_mac.mm b/ui/native_theme/native_theme_mac.mm index c8b39a3..037ec20 100644 --- a/ui/native_theme/native_theme_mac.mm +++ b/ui/native_theme/native_theme_mac.mm
@@ -256,15 +256,15 @@ cc::PaintCanvas* canvas, const gfx::Size& size, const MenuBackgroundExtraParams& menu_background) const { - cc::PaintFlags paint; - paint.setAntiAlias(true); + cc::PaintFlags flags; + flags.setAntiAlias(true); if (base::mac::IsOS10_9()) - paint.setColor(kMenuPopupBackgroundColorMavericks); + flags.setColor(kMenuPopupBackgroundColorMavericks); else - paint.setColor(kMenuPopupBackgroundColor); + flags.setColor(kMenuPopupBackgroundColor); const SkScalar radius = SkIntToScalar(menu_background.corner_radius); SkRect rect = gfx::RectToSkRect(gfx::Rect(size)); - canvas->drawRoundRect(rect, radius, radius, paint); + canvas->drawRoundRect(rect, radius, radius, flags); } void NativeThemeMac::PaintMenuItemBackground( @@ -272,7 +272,7 @@ State state, const gfx::Rect& rect, const MenuItemExtraParams& menu_item) const { - cc::PaintFlags paint; + cc::PaintFlags flags; switch (state) { case NativeTheme::kNormal: case NativeTheme::kDisabled: @@ -283,8 +283,8 @@ // pick colors. The System color "selectedMenuItemColor" is actually still // blue for Graphite. And while "keyboardFocusIndicatorColor" does change, // and is a good shade of gray, it's not blue enough for the Blue theme. - paint.setColor(GetSystemColor(kColorId_FocusedMenuItemBackgroundColor)); - canvas->drawRect(gfx::RectToSkRect(rect), paint); + flags.setColor(GetSystemColor(kColorId_FocusedMenuItemBackgroundColor)); + canvas->drawRect(gfx::RectToSkRect(rect), flags); break; default: NOTREACHED(); @@ -409,32 +409,32 @@ else shape.setRect(bounds); - cc::PaintFlags paint; - paint.setStyle(cc::PaintFlags::kFill_Style); - paint.setAntiAlias(true); + cc::PaintFlags flags; + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setAntiAlias(true); // First draw the darker "outer" border, with its gradient and shadow. Inside // a tab strip, this will draw over the outer border and inner separator. - paint.setLooper(gfx::CreateShadowDrawLooper(shadows)); - paint.setShader( + flags.setLooper(gfx::CreateShadowDrawLooper(shadows)); + flags.setShader( cc::WrapSkShader(GetButtonBorderShader(type, shape.height()))); - canvas->drawRRect(shape, paint); + canvas->drawRRect(shape, flags); // Then, inset the rounded rect and draw over that with the inner gradient. shape.inset(kBorderThickness, kBorderThickness); - paint.setLooper(nullptr); - paint.setShader( + flags.setLooper(nullptr); + flags.setShader( cc::WrapSkShader(GetButtonBackgroundShader(type, shape.height()))); - canvas->drawRRect(shape, paint); + canvas->drawRRect(shape, flags); if (!focus) return; SkRRect outer_shape; shape.outset(kFocusRingThickness, kFocusRingThickness, &outer_shape); - paint.setShader(nullptr); - paint.setColor(kFocusRingColor); - canvas->drawDRRect(outer_shape, shape, paint); + flags.setShader(nullptr); + flags.setColor(kFocusRingColor); + canvas->drawDRRect(outer_shape, shape, flags); } NativeThemeMac::NativeThemeMac() {
diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc index 186cee9f..7f30ddb 100644 --- a/ui/native_theme/native_theme_win.cc +++ b/ui/native_theme/native_theme_win.cc
@@ -60,7 +60,7 @@ COLOR_WINDOWTEXT, }; -void SetCheckerboardShader(cc::PaintFlags* paint, const RECT& align_rect) { +void SetCheckerboardShader(cc::PaintFlags* flags, const RECT& align_rect) { // Create a 2x2 checkerboard pattern using the 3D face and highlight colors. const SkColor face = color_utils::GetSysSkColor(COLOR_3DFACE); const SkColor highlight = color_utils::GetSysSkColor(COLOR_3DHILIGHT); @@ -81,7 +81,7 @@ SkMatrix local_matrix; local_matrix.setTranslate(SkIntToScalar(align_rect.left), SkIntToScalar(align_rect.top)); - paint->setShader( + flags->setShader( SkShader::MakeBitmapShader(bitmap, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &local_matrix)); } @@ -378,25 +378,25 @@ void NativeThemeWin::PaintMenuSeparator(SkCanvas* canvas, const gfx::Rect& rect) const { - cc::PaintFlags paint; - paint.setColor(GetSystemColor(NativeTheme::kColorId_MenuSeparatorColor)); + cc::PaintFlags flags; + flags.setColor(GetSystemColor(NativeTheme::kColorId_MenuSeparatorColor)); int position_y = rect.y() + rect.height() / 2; - canvas->drawLine(rect.x(), position_y, rect.right(), position_y, paint); + canvas->drawLine(rect.x(), position_y, rect.right(), position_y, flags); } void NativeThemeWin::PaintMenuGutter(SkCanvas* canvas, const gfx::Rect& rect) const { - cc::PaintFlags paint; - paint.setColor(GetSystemColor(NativeTheme::kColorId_MenuSeparatorColor)); + cc::PaintFlags flags; + flags.setColor(GetSystemColor(NativeTheme::kColorId_MenuSeparatorColor)); int position_x = rect.x() + rect.width() / 2; - canvas->drawLine(position_x, rect.y(), position_x, rect.bottom(), paint); + canvas->drawLine(position_x, rect.y(), position_x, rect.bottom(), flags); } void NativeThemeWin::PaintMenuBackground(SkCanvas* canvas, const gfx::Rect& rect) const { - cc::PaintFlags paint; - paint.setColor(GetSystemColor(NativeTheme::kColorId_MenuBackgroundColor)); - canvas->drawRect(gfx::RectToSkRect(rect), paint); + cc::PaintFlags flags; + flags.setColor(GetSystemColor(NativeTheme::kColorId_MenuBackgroundColor)); + canvas->drawRect(gfx::RectToSkRect(rect), flags); } void NativeThemeWin::PaintDirect(SkCanvas* destination_canvas, @@ -1321,11 +1321,11 @@ (system_colors_[COLOR_SCROLLBAR] != system_colors_[COLOR_WINDOW])) { FillRect(hdc, &rect_win, reinterpret_cast<HBRUSH>(COLOR_SCROLLBAR + 1)); } else { - cc::PaintFlags paint; + cc::PaintFlags flags; RECT align_rect = gfx::Rect(extra.track_x, extra.track_y, extra.track_width, extra.track_height).ToRECT(); - SetCheckerboardShader(&paint, align_rect); - canvas->drawIRect(skia::RECTToSkIRect(rect_win), paint); + SetCheckerboardShader(&flags, align_rect); + canvas->drawIRect(skia::RECTToSkIRect(rect_win), flags); } if (extra.classic_state & DFCS_PUSHED) InvertRect(hdc, &rect_win); @@ -1440,11 +1440,11 @@ // If the button is pressed, draw hatching. if (extra.classic_state & DFCS_PUSHED) { - cc::PaintFlags paint; - SetCheckerboardShader(&paint, rect_win); + cc::PaintFlags flags; + SetCheckerboardShader(&flags, rect_win); // Fill all three pieces with the pattern. - canvas->drawIRect(skia::RECTToSkIRect(top_section), paint); + canvas->drawIRect(skia::RECTToSkIRect(top_section), flags); SkScalar left_triangle_top = SkIntToScalar(left_half.top); SkScalar left_triangle_right = SkIntToScalar(left_half.right); @@ -1454,7 +1454,7 @@ left_triangle.lineTo(left_triangle_right, SkIntToScalar(left_half.bottom)); left_triangle.close(); - canvas->drawPath(left_triangle, paint); + canvas->drawPath(left_triangle, flags); SkScalar right_triangle_left = SkIntToScalar(right_half.left); SkScalar right_triangle_top = SkIntToScalar(right_half.top); @@ -1465,7 +1465,7 @@ right_triangle.lineTo(right_triangle_left, SkIntToScalar(right_half.bottom)); right_triangle.close(); - canvas->drawPath(right_triangle, paint); + canvas->drawPath(right_triangle, flags); } } return S_OK;
diff --git a/ui/strings/ui_strings.grd b/ui/strings/ui_strings.grd index 8ec594a..1b641302 100644 --- a/ui/strings/ui_strings.grd +++ b/ui/strings/ui_strings.grd
@@ -696,7 +696,7 @@ To exit calibration press Esc. </message> <message name="IDS_DISPLAY_TOUCH_CALIBRATION_HINT_LABEL_TEXT" desc="Title of the hint message to inform the user what the next step is in touch calibration is"> - Define your touchscreen + Calibrate your touchscreen </message> <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.
diff --git a/ui/vector_icons/BUILD.gn b/ui/vector_icons/BUILD.gn new file mode 100644 index 0000000..c299793 --- /dev/null +++ b/ui/vector_icons/BUILD.gn
@@ -0,0 +1,25 @@ +# 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. + +import("//ui/vector_icons/vector_icons.gni") + +aggregate_vector_icons("ui_vector_icons") { + icon_directory = "." + + icons = [ + "close.1x.icon", + "close.icon", + ] +} + +static_library("vector_icons") { + sources = get_target_outputs(":ui_vector_icons") + sources += [ "//ui/gfx/vector_icon_types.h" ] + + deps = [ + ":ui_vector_icons", + "//base", + "//skia", + ] +}
diff --git a/ui/vector_icons/DEPS b/ui/vector_icons/DEPS new file mode 100644 index 0000000..b7a2ad6 --- /dev/null +++ b/ui/vector_icons/DEPS
@@ -0,0 +1,5 @@ +include_rules = [ + "+base", + "+skia", + "+ui/gfx", +]
diff --git a/ui/vector_icons/OWNERS b/ui/vector_icons/OWNERS new file mode 100644 index 0000000..658a9f5 --- /dev/null +++ b/ui/vector_icons/OWNERS
@@ -0,0 +1 @@ +estade@chromium.org
diff --git a/ui/gfx/vector_icons/bar_close.1x.icon b/ui/vector_icons/close.1x.icon similarity index 100% rename from ui/gfx/vector_icons/bar_close.1x.icon rename to ui/vector_icons/close.1x.icon
diff --git a/ui/gfx/vector_icons/bar_close.icon b/ui/vector_icons/close.icon similarity index 100% rename from ui/gfx/vector_icons/bar_close.icon rename to ui/vector_icons/close.icon
diff --git a/ui/vector_icons/vector_icons.cc.template b/ui/vector_icons/vector_icons.cc.template new file mode 100644 index 0000000..70a18eb --- /dev/null +++ b/ui/vector_icons/vector_icons.cc.template
@@ -0,0 +1,25 @@ +// 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. + +// vector_icons.cc.template is used to generate vector_icons.cc. Edit the former +// rather than the latter. + +#include "ui/vector_icons/vector_icons.h" + +#include "base/logging.h" +#include "ui/gfx/vector_icon_types.h" + +#define PATH_ELEMENT_TEMPLATE(path_name, ...) \ +static constexpr gfx::PathElement path_name[] = {__VA_ARGS__}; + +#define VECTOR_ICON_TEMPLATE(icon_name, path_name, path_name_1x) \ +const gfx::VectorIcon icon_name = { path_name , path_name_1x }; + +namespace ui { + +using namespace gfx; + +TEMPLATE_PLACEHOLDER + +} // namespace ash
diff --git a/ui/vector_icons/vector_icons.gni b/ui/vector_icons/vector_icons.gni new file mode 100644 index 0000000..f22984d --- /dev/null +++ b/ui/vector_icons/vector_icons.gni
@@ -0,0 +1,60 @@ +# 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. + +# Creates an action that aggregates vector icon files (.icon) into a C++ file. +# In addition to running the action, the outputs should be added to another +# target's sources for compilation. +# +# Parameters +# +# icons (required) +# A list of icon filenames to use as inputs. +# +# icon_directory (required) +# The path component of the location of the icons, relative to the current +# directory. For example, if the invoking BUILD file exists in //foo/bar +# and the icons are in //foo/bar/vector_icons/, then icon_directory should +# be set to "vector_icons". There must also be template files in this +# directory. +# +# Example +# +# See BUILD.gn in this directory (//ui/vector_icons/) for an example. +template("aggregate_vector_icons") { + assert(defined(invoker.icons), + "Need icons in $target_name listing the icon files.") + assert( + defined(invoker.icon_directory), + "Need icon_directory in $target_name where the icons and templates live.") + + action(target_name) { + visibility = [ ":*" ] + + script = "//ui/gfx/vector_icons/aggregate_vector_icons.py" + + output_cc = "$target_gen_dir/vector_icons.cc" + output_h = "$target_gen_dir/vector_icons.h" + + templates = [ + "vector_icons.cc.template", + "vector_icons.h.template", + ] + inputs = rebase_path(templates + invoker.icons, ".", invoker.icon_directory) + + outputs = [ + output_cc, + output_h, + ] + + response_file_contents = + rebase_path(invoker.icons, root_build_dir, invoker.icon_directory) + + args = [ + "--working_directory=" + rebase_path(invoker.icon_directory), + "--file_list={{response_file_name}}", + "--output_cc=" + rebase_path(output_cc, root_build_dir), + "--output_h=" + rebase_path(output_h, root_build_dir), + ] + } +}
diff --git a/ui/vector_icons/vector_icons.h.template b/ui/vector_icons/vector_icons.h.template new file mode 100644 index 0000000..9b8861c --- /dev/null +++ b/ui/vector_icons/vector_icons.h.template
@@ -0,0 +1,26 @@ +// 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. + +// vector_icons.h.template is used to generate vector_icons.h. Edit the former +// rather than the latter. + +#ifndef UI_VECTOR_ICONS_VECTOR_ICONS_H_ +#define UI_VECTOR_ICONS_VECTOR_ICONS_H_ + +namespace gfx { +struct VectorIcon; +} + +#define VECTOR_ICON_TEMPLATE_H(icon_name) \ +extern const gfx::VectorIcon icon_name; + +namespace ui { + +TEMPLATE_PLACEHOLDER + +} // namespace ui + +#undef VECTOR_ICON_TEMPLATE_H + +#endif // UI_VECTOR_ICONS_VECTOR_ICONS_H_
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn index d770d90..0f0696a 100644 --- a/ui/views/BUILD.gn +++ b/ui/views/BUILD.gn
@@ -7,57 +7,34 @@ import("//testing/test.gni") import("//ui/base/ui_features.gni") import("//ui/ozone/ozone.gni") +import("//ui/vector_icons/vector_icons.gni") config("flags") { defines = [ "TOOLKIT_VIEWS=1" ] } -action("aggregate_vector_icons") { - visibility = [ ":*" ] - - script = "//ui/gfx/vector_icons/aggregate_vector_icons.py" +aggregate_vector_icons("views_vector_icons") { + icon_directory = "vector_icons" icons = [ - "vector_icons/checkbox_active.icon", - "vector_icons/checkbox_normal.icon", - "vector_icons/menu_check.1x.icon", - "vector_icons/menu_check.icon", - "vector_icons/menu_radio_empty.icon", - "vector_icons/menu_radio_selected.icon", - "vector_icons/radio_button_active.icon", - "vector_icons/radio_button_normal.icon", - "vector_icons/submenu_arrow.1x.icon", - "vector_icons/submenu_arrow.icon", + "checkbox_active.icon", + "checkbox_normal.icon", + "menu_check.1x.icon", + "menu_check.icon", + "menu_radio_empty.icon", + "menu_radio_selected.icon", + "radio_button_active.icon", + "radio_button_normal.icon", + "submenu_arrow.1x.icon", + "submenu_arrow.icon", ] if (is_mac) { icons += [ - "vector_icons/combobox_arrow_mac_enabled.icon", - "vector_icons/combobox_arrow_mac_disabled.icon", + "combobox_arrow_mac_enabled.icon", + "combobox_arrow_mac_disabled.icon", ] } - - output_cc = "$target_gen_dir/vector_icons.cc" - output_h = "$target_gen_dir/vector_icons.h" - - inputs = icons - inputs += [ - "vector_icons/vector_icons.cc.template", - "vector_icons/vector_icons.h.template", - ] - outputs = [ - output_cc, - output_h, - ] - - response_file_contents = rebase_path(icons, root_build_dir) - - args = [ - "--working_directory=" + rebase_path("./vector_icons"), - "--file_list={{response_file_name}}", - "--output_cc=" + rebase_path(output_cc, root_build_dir), - "--output_h=" + rebase_path(output_h, root_build_dir), - ] } component("views") { @@ -436,7 +413,7 @@ "word_lookup_client.h", ] - sources += get_target_outputs(":aggregate_vector_icons") + sources += get_target_outputs(":views_vector_icons") configs += [ "//build/config:precompiled_headers", @@ -448,7 +425,7 @@ defines = [ "VIEWS_IMPLEMENTATION" ] deps = [ - ":aggregate_vector_icons", + ":views_vector_icons", "//base:i18n", "//base/third_party/dynamic_annotations", "//cc/paint", @@ -477,6 +454,7 @@ "//ui/events/platform", "//ui/gfx", "//ui/gfx/geometry", + "//ui/vector_icons", "//ui/views/resources", ]
diff --git a/ui/views/DEPS b/ui/views/DEPS index 7cfc13b..5798304 100644 --- a/ui/views/DEPS +++ b/ui/views/DEPS
@@ -17,6 +17,7 @@ "+ui/resources/grit/ui_resources.h", "+ui/strings/grit/ui_strings.h", "+ui/touch_selection", + "+ui/vector_icons", "+ui/wm/core", "+ui/wm/public",
diff --git a/ui/views/animation/ink_drop_host_view.h b/ui/views/animation/ink_drop_host_view.h index 9ca5955..995e4d5c 100644 --- a/ui/views/animation/ink_drop_host_view.h +++ b/ui/views/animation/ink_drop_host_view.h
@@ -53,6 +53,11 @@ // subclasses/clients to specify the flavor of ink drop. void SetInkDropMode(InkDropMode ink_drop_mode); + void set_ink_drop_visible_opacity(float visible_opacity) { + ink_drop_visible_opacity_ = visible_opacity; + } + float ink_drop_visible_opacity() const { return ink_drop_visible_opacity_; } + protected: static constexpr int kInkDropSmallCornerRadius = 2; static constexpr int kInkDropLargeCornerRadius = 4; @@ -64,11 +69,6 @@ // with the SquareInkDropRipple animation durations. static gfx::Size CalculateLargeInkDropSize(const gfx::Size& small_size); - void set_ink_drop_visible_opacity(float visible_opacity) { - ink_drop_visible_opacity_ = visible_opacity; - } - float ink_drop_visible_opacity() const { return ink_drop_visible_opacity_; } - // Returns the default InkDropRipple centered on |center_point|. std::unique_ptr<InkDropRipple> CreateDefaultInkDropRipple( const gfx::Point& center_point,
diff --git a/ui/views/animation/ink_drop_mask.cc b/ui/views/animation/ink_drop_mask.cc index a398136..de839a9 100644 --- a/ui/views/animation/ink_drop_mask.cc +++ b/ui/views/animation/ink_drop_mask.cc
@@ -42,15 +42,15 @@ corner_radius_(corner_radius) {} void RoundRectInkDropMask::OnPaintLayer(const ui::PaintContext& context) { - cc::PaintFlags paint; - paint.setAlpha(255); - paint.setStyle(cc::PaintFlags::kFill_Style); - paint.setAntiAlias(true); + cc::PaintFlags flags; + flags.setAlpha(255); + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setAntiAlias(true); ui::PaintRecorder recorder(context, layer()->size()); gfx::Rect bounds = layer()->bounds(); bounds.Inset(mask_insets_); - recorder.canvas()->DrawRoundRect(bounds, corner_radius_, paint); + recorder.canvas()->DrawRoundRect(bounds, corner_radius_, flags); } // CircleInkDropMask @@ -63,13 +63,13 @@ mask_radius_(mask_radius) {} void CircleInkDropMask::OnPaintLayer(const ui::PaintContext& context) { - cc::PaintFlags paint; - paint.setAlpha(255); - paint.setStyle(cc::PaintFlags::kFill_Style); - paint.setAntiAlias(true); + cc::PaintFlags flags; + flags.setAlpha(255); + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setAntiAlias(true); ui::PaintRecorder recorder(context, layer()->size()); - recorder.canvas()->DrawCircle(mask_center_, mask_radius_, paint); + recorder.canvas()->DrawCircle(mask_center_, mask_radius_, flags); } } // namespace views
diff --git a/ui/views/animation/ink_drop_painted_layer_delegates.cc b/ui/views/animation/ink_drop_painted_layer_delegates.cc index 4612abdf..388fa7b 100644 --- a/ui/views/animation/ink_drop_painted_layer_delegates.cc +++ b/ui/views/animation/ink_drop_painted_layer_delegates.cc
@@ -58,15 +58,15 @@ } void CircleLayerDelegate::OnPaintLayer(const ui::PaintContext& context) { - cc::PaintFlags paint; - paint.setColor(color()); - paint.setAntiAlias(true); - paint.setStyle(cc::PaintFlags::kFill_Style); + cc::PaintFlags flags; + flags.setColor(color()); + flags.setAntiAlias(true); + flags.setStyle(cc::PaintFlags::kFill_Style); ui::PaintRecorder recorder(context, GetPaintedBounds().size()); gfx::Canvas* canvas = recorder.canvas(); - canvas->DrawCircle(GetPaintedBounds().CenterPoint(), radius_, paint); + canvas->DrawCircle(GetPaintedBounds().CenterPoint(), radius_, flags); } //////////////////////////////////////////////////////////////////////////////// @@ -84,14 +84,14 @@ } void RectangleLayerDelegate::OnPaintLayer(const ui::PaintContext& context) { - cc::PaintFlags paint; - paint.setColor(color()); - paint.setAntiAlias(true); - paint.setStyle(cc::PaintFlags::kFill_Style); + cc::PaintFlags flags; + flags.setColor(color()); + flags.setAntiAlias(true); + flags.setStyle(cc::PaintFlags::kFill_Style); ui::PaintRecorder recorder(context, size_); gfx::Canvas* canvas = recorder.canvas(); - canvas->DrawRect(GetPaintedBounds(), paint); + canvas->DrawRect(GetPaintedBounds(), flags); } //////////////////////////////////////////////////////////////////////////////// @@ -115,13 +115,13 @@ void RoundedRectangleLayerDelegate::OnPaintLayer( const ui::PaintContext& context) { - cc::PaintFlags paint; - paint.setColor(color()); - paint.setAntiAlias(true); - paint.setStyle(cc::PaintFlags::kFill_Style); + cc::PaintFlags flags; + flags.setColor(color()); + flags.setAntiAlias(true); + flags.setStyle(cc::PaintFlags::kFill_Style); ui::PaintRecorder recorder(context, size_); - recorder.canvas()->DrawRoundRect(GetPaintedBounds(), corner_radius_, paint); + recorder.canvas()->DrawRoundRect(GetPaintedBounds(), corner_radius_, flags); } //////////////////////////////////////////////////////////////////////////////// @@ -153,10 +153,10 @@ } void BorderShadowLayerDelegate::OnPaintLayer(const ui::PaintContext& context) { - cc::PaintFlags paint; - paint.setStyle(cc::PaintFlags::kFill_Style); - paint.setAntiAlias(true); - paint.setColor(fill_color_); + cc::PaintFlags flags; + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setAntiAlias(true); + flags.setColor(fill_color_); gfx::RectF rrect_bounds = gfx::RectF(bounds_ - GetPaintedBounds().OffsetFromOrigin()); @@ -165,13 +165,13 @@ // First the fill color. ui::PaintRecorder recorder(context, GetPaintedBounds().size()); - recorder.canvas()->sk_canvas()->drawRRect(r_rect, paint); + recorder.canvas()->sk_canvas()->drawRRect(r_rect, flags); // Now the shadow. - paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadows_)); + flags.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadows_)); recorder.canvas()->sk_canvas()->clipRRect(r_rect, SkClipOp::kDifference, true); - recorder.canvas()->sk_canvas()->drawRRect(r_rect, paint); + recorder.canvas()->sk_canvas()->drawRRect(r_rect, flags); } } // namespace views
diff --git a/ui/views/border.cc b/ui/views/border.cc index c4008bf..14e6d302 100644 --- a/ui/views/border.cc +++ b/ui/views/border.cc
@@ -88,16 +88,16 @@ : thickness_(thickness), corner_radius_(corner_radius), color_(color) {} void RoundedRectBorder::Paint(const View& view, gfx::Canvas* canvas) { - cc::PaintFlags paint; - paint.setStrokeWidth(thickness_); - paint.setColor(color_); - paint.setStyle(cc::PaintFlags::kStroke_Style); - paint.setAntiAlias(true); + cc::PaintFlags flags; + flags.setStrokeWidth(thickness_); + flags.setColor(color_); + flags.setStyle(cc::PaintFlags::kStroke_Style); + flags.setAntiAlias(true); float half_thickness = thickness_ / 2.0f; gfx::RectF bounds(view.GetLocalBounds()); bounds.Inset(half_thickness, half_thickness); - canvas->DrawRoundRect(bounds, corner_radius_, paint); + canvas->DrawRoundRect(bounds, corner_radius_, flags); } gfx::Insets RoundedRectBorder::GetInsets() const {
diff --git a/ui/views/bubble/bubble_border.cc b/ui/views/bubble/bubble_border.cc index a93bcb0..f81e8ad 100644 --- a/ui/views/bubble/bubble_border.cc +++ b/ui/views/bubble/bubble_border.cc
@@ -510,11 +510,11 @@ canvas->DrawImageInt(*GetArrowImage(), arrow_bounds.x(), arrow_bounds.y()); SkPath path; GetArrowPathFromArrowBounds(arrow_bounds, &path); - cc::PaintFlags paint; - paint.setStyle(cc::PaintFlags::kFill_Style); - paint.setColor(background_color_); + cc::PaintFlags flags; + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setColor(background_color_); - canvas->DrawPath(path, paint); + canvas->DrawPath(path, flags); } SkRRect BubbleBorder::GetClientRect(const View& view) const { @@ -530,7 +530,7 @@ gfx::ScopedCanvas scoped(canvas); - cc::PaintFlags paint; + cc::PaintFlags flags; std::vector<gfx::ShadowValue> shadows; // gfx::ShadowValue counts blur pixels both inside and outside the shape, // whereas these blur values only describe the outside portion, hence they @@ -539,9 +539,9 @@ 2 * kSmallShadowBlur, kSmallShadowColor); shadows.emplace_back(gfx::Vector2d(0, kLargeShadowVerticalOffset), 2 * kLargeShadowBlur, kLargeShadowColor); - paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadows)); - paint.setColor(SkColorSetA(SK_ColorBLACK, 0x26)); - paint.setAntiAlias(true); + flags.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadows)); + flags.setColor(SkColorSetA(SK_ColorBLACK, 0x26)); + flags.setAntiAlias(true); SkRRect r_rect = GetClientRect(view); canvas->sk_canvas()->clipRRect(r_rect, SkClipOp::kDifference, @@ -551,7 +551,7 @@ const SkScalar one_pixel = SkFloatToScalar(kBorderStrokeThicknessPx / canvas->image_scale()); r_rect.inset(-one_pixel, -one_pixel); - canvas->sk_canvas()->drawRRect(r_rect, paint); + canvas->sk_canvas()->drawRRect(r_rect, flags); } void BubbleBorder::PaintNoAssets(const View& view, gfx::Canvas* canvas) { @@ -570,15 +570,15 @@ canvas->DrawColor(border_->background_color()); // Fill the contents with a round-rect region to match the border images. - cc::PaintFlags paint; - paint.setAntiAlias(true); - paint.setStyle(cc::PaintFlags::kFill_Style); - paint.setColor(border_->background_color()); + cc::PaintFlags flags; + flags.setAntiAlias(true); + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setColor(border_->background_color()); SkPath path; gfx::RectF bounds(view->GetLocalBounds()); bounds.Inset(gfx::InsetsF(border_->GetInsets())); - canvas->DrawRoundRect(bounds, border_->GetBorderCornerRadius(), paint); + canvas->DrawRoundRect(bounds, border_->GetBorderCornerRadius(), flags); } } // namespace views
diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc index 80c41c0..14f5622 100644 --- a/ui/views/bubble/bubble_frame_view.cc +++ b/ui/views/bubble/bubble_frame_view.cc
@@ -20,10 +20,10 @@ #include "ui/gfx/geometry/vector2d.h" #include "ui/gfx/path.h" #include "ui/gfx/skia_util.h" -#include "ui/gfx/vector_icons_public.h" #include "ui/native_theme/native_theme.h" #include "ui/resources/grit/ui_resources.h" #include "ui/strings/grit/ui_strings.h" +#include "ui/vector_icons/vector_icons.h" #include "ui/views/bubble/bubble_border.h" #include "ui/views/controls/button/vector_icon_button.h" #include "ui/views/controls/image_view.h" @@ -31,6 +31,7 @@ #include "ui/views/layout/box_layout.h" #include "ui/views/layout/layout_constants.h" #include "ui/views/resources/grit/views_resources.h" +#include "ui/views/views_delegate.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" #include "ui/views/window/client_view.h" @@ -45,14 +46,6 @@ // Color of the top border of the footnote. const SkColor kFootnoteBorderColor = SkColorSetRGB(229, 229, 229); -constexpr int kClosePaddingRight = 7; -constexpr int kClosePaddingTop = 7; - -// The MD spec states that the center of the "x" should be 16x16 from the top -// right of the dialog. -constexpr int kClosePaddingRightMd = 4; -constexpr int kClosePaddingTopMd = 4; - // Get the |vertical| or horizontal amount that |available_bounds| overflows // |window_bounds|. int GetOffScreenLength(const gfx::Rect& available_bounds, @@ -119,7 +112,7 @@ ImageButton* close_button = nullptr; if (ui::MaterialDesignController::IsSecondaryUiMaterial()) { VectorIconButton* close = new VectorIconButton(delegate); - close->SetIcon(gfx::VectorIconId::BAR_CLOSE); + close->SetIcon(ui::kCloseIcon); close_button = close; } else { ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); @@ -321,15 +314,11 @@ return; // The close button is positioned somewhat closer to the edge of the bubble. - gfx::Point close_position = contents_bounds.top_right(); - if (ui::MaterialDesignController::IsSecondaryUiMaterial()) { - close_position += gfx::Vector2d(-close_->width() - kClosePaddingRightMd, - kClosePaddingTopMd); - } else { - close_position += - gfx::Vector2d(-close_->width() - kClosePaddingRight, kClosePaddingTop); - } - close_->SetPosition(close_position); + const int close_margin = + ViewsDelegate::GetInstance()->GetDialogCloseButtonMargin(); + close_->SetPosition( + gfx::Point(contents_bounds.right() - close_margin - close_->width(), + contents_bounds.y() + close_margin)); gfx::Size title_icon_pref_size(title_icon_->GetPreferredSize()); int padding = 0;
diff --git a/ui/views/bubble/tray_bubble_view.cc b/ui/views/bubble/tray_bubble_view.cc index 4aa577ac..3d7a93e 100644 --- a/ui/views/bubble/tray_bubble_view.cc +++ b/ui/views/bubble/tray_bubble_view.cc
@@ -113,11 +113,11 @@ void TrayBubbleContentMask::OnPaintLayer(const ui::PaintContext& context) { ui::PaintRecorder recorder(context, layer()->size()); - cc::PaintFlags paint; - paint.setAlpha(255); - paint.setStyle(cc::PaintFlags::kFill_Style); + cc::PaintFlags flags; + flags.setAlpha(255); + flags.setStyle(cc::PaintFlags::kFill_Style); gfx::Rect rect(layer()->bounds().size()); - recorder.canvas()->DrawRoundRect(rect, corner_radius_, paint); + recorder.canvas()->DrawRoundRect(rect, corner_radius_, flags); } void TrayBubbleContentMask::OnDeviceScaleFactorChanged(
diff --git a/ui/views/color_chooser/color_chooser_view.cc b/ui/views/color_chooser/color_chooser_view.cc index a98be0e..411cdb9 100644 --- a/ui/views/color_chooser/color_chooser_view.cc +++ b/ui/views/color_chooser/color_chooser_view.cc
@@ -103,10 +103,10 @@ points[1].iset(rect.width() + 1, 0); else points[1].iset(0, rect.height() + 1); - cc::PaintFlags paint; - paint.setShader(cc::WrapSkShader(SkGradientShader::MakeLinear( + cc::PaintFlags flags; + flags.setShader(cc::WrapSkShader(SkGradientShader::MakeLinear( points, colors, NULL, 2, SkShader::kClamp_TileMode))); - canvas->DrawRect(rect, paint); + canvas->DrawRect(rect, flags); } } // namespace @@ -211,11 +211,11 @@ SkIntToScalar(width()) - SK_ScalarHalf, SkIntToScalar(level_ - kHueIndicatorSize)); - cc::PaintFlags indicator_paint; - indicator_paint.setColor(SK_ColorBLACK); - indicator_paint.setStyle(cc::PaintFlags::kFill_Style); - canvas->DrawPath(left_indicator_path, indicator_paint); - canvas->DrawPath(right_indicator_path, indicator_paint); + cc::PaintFlags indicator_flags; + indicator_flags.setColor(SK_ColorBLACK); + indicator_flags.setStyle(cc::PaintFlags::kFill_Style); + canvas->DrawPath(left_indicator_path, indicator_flags); + canvas->DrawPath(right_indicator_path, indicator_flags); } ////////////////////////////////////////////////////////////////////////////////
diff --git a/ui/views/controls/button/checkbox.cc b/ui/views/controls/button/checkbox.cc index 290da30..91d3a23 100644 --- a/ui/views/controls/button/checkbox.cc +++ b/ui/views/controls/button/checkbox.cc
@@ -142,15 +142,15 @@ if (!UseMd() || !HasFocus()) return; - cc::PaintFlags focus_paint; - focus_paint.setAntiAlias(true); - focus_paint.setColor( + cc::PaintFlags focus_flags; + focus_flags.setAntiAlias(true); + focus_flags.setColor( SkColorSetA(GetNativeTheme()->GetSystemColor( ui::NativeTheme::kColorId_FocusedBorderColor), 0x66)); - focus_paint.setStyle(cc::PaintFlags::kStroke_Style); - focus_paint.setStrokeWidth(2); - PaintFocusRing(canvas, focus_paint); + focus_flags.setStyle(cc::PaintFlags::kStroke_Style); + focus_flags.setStrokeWidth(2); + PaintFocusRing(canvas, focus_flags); } void Checkbox::OnFocus() { @@ -215,9 +215,9 @@ } void Checkbox::PaintFocusRing(gfx::Canvas* canvas, - const cc::PaintFlags& paint) { + const cc::PaintFlags& flags) { gfx::RectF focus_rect(image()->bounds()); - canvas->DrawRoundRect(focus_rect, 2.f, paint); + canvas->DrawRoundRect(focus_rect, 2.f, flags); } const gfx::VectorIcon& Checkbox::GetVectorIcon() const {
diff --git a/ui/views/controls/button/checkbox.h b/ui/views/controls/button/checkbox.h index 47e07c34..407c4d39 100644 --- a/ui/views/controls/button/checkbox.h +++ b/ui/views/controls/button/checkbox.h
@@ -60,7 +60,7 @@ const gfx::ImageSkia& image); // Paints a focus indicator for the view. - virtual void PaintFocusRing(gfx::Canvas* canvas, const cc::PaintFlags& paint); + virtual void PaintFocusRing(gfx::Canvas* canvas, const cc::PaintFlags& flags); // Gets the vector icon to use based on the current state of |checked_|. virtual const gfx::VectorIcon& GetVectorIcon() const;
diff --git a/ui/views/controls/button/custom_button.h b/ui/views/controls/button/custom_button.h index 4b72cda..44c2e111 100644 --- a/ui/views/controls/button/custom_button.h +++ b/ui/views/controls/button/custom_button.h
@@ -97,6 +97,9 @@ } void set_ink_drop_base_color(SkColor color) { ink_drop_base_color_ = color; } + void set_has_ink_drop_action_on_click(bool has_ink_drop_action_on_click) { + has_ink_drop_action_on_click_ = has_ink_drop_action_on_click; + } void SetHotTracked(bool is_hot_tracked); bool IsHotTracked() const; @@ -153,10 +156,6 @@ // we simply return IsTriggerableEvent(event). virtual bool ShouldEnterPushedState(const ui::Event& event); - void set_has_ink_drop_action_on_click(bool has_ink_drop_action_on_click) { - has_ink_drop_action_on_click_ = has_ink_drop_action_on_click; - } - // Returns true if the button should enter hovered state; that is, if the // mouse is over the button, and no other window has capture (which would // prevent the button from receiving MouseExited events and updating its
diff --git a/ui/views/controls/button/label_button_border.cc b/ui/views/controls/button/label_button_border.cc index a5116d0..cc6e983 100644 --- a/ui/views/controls/button/label_button_border.cc +++ b/ui/views/controls/button/label_button_border.cc
@@ -154,10 +154,10 @@ } // Then modulate the foreground by alpha, and blend using kPlus_Mode. - cc::PaintFlags paint; - paint.setAlpha(fg_alpha); - paint.setBlendMode(SkBlendMode::kPlus); - canvas->sk_canvas()->saveLayer(&sk_rect, &paint); + cc::PaintFlags flags; + flags.setAlpha(fg_alpha); + flags.setBlendMode(SkBlendMode::kPlus); + canvas->sk_canvas()->saveLayer(&sk_rect, &flags); state = native_theme_delegate->GetForegroundThemeState(&extra); PaintHelper(this, canvas, state, rect, extra); } else {
diff --git a/ui/views/controls/button/radio_button.cc b/ui/views/controls/button/radio_button.cc index 0a2c89c8..ca85989 100644 --- a/ui/views/controls/button/radio_button.cc +++ b/ui/views/controls/button/radio_button.cc
@@ -148,9 +148,9 @@ } void RadioButton::PaintFocusRing(gfx::Canvas* canvas, - const cc::PaintFlags& paint) { + const cc::PaintFlags& flags) { canvas->DrawCircle(gfx::RectF(image()->bounds()).CenterPoint(), - image()->width() / 2, paint); + image()->width() / 2, flags); } const gfx::VectorIcon& RadioButton::GetVectorIcon() const {
diff --git a/ui/views/controls/button/radio_button.h b/ui/views/controls/button/radio_button.h index b3d581e..f27197a 100644 --- a/ui/views/controls/button/radio_button.h +++ b/ui/views/controls/button/radio_button.h
@@ -37,7 +37,7 @@ // Overridden from Checkbox: void SetChecked(bool checked) override; void PaintFocusRing(gfx::Canvas* canvas, - const cc::PaintFlags& paint) override; + const cc::PaintFlags& flags) override; const gfx::VectorIcon& GetVectorIcon() const override; private:
diff --git a/ui/views/controls/button/toggle_button.cc b/ui/views/controls/button/toggle_button.cc index 0e39d93..7f01ba3 100644 --- a/ui/views/controls/button/toggle_button.cc +++ b/ui/views/controls/button/toggle_button.cc
@@ -78,15 +78,15 @@ ui::NativeTheme::kColorId_LabelEnabledColor), 0x99)); shadows.push_back(shadow.Scale(dsf)); - cc::PaintFlags thumb_paint; - thumb_paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadows)); - thumb_paint.setAntiAlias(true); + cc::PaintFlags thumb_flags; + thumb_flags.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadows)); + thumb_flags.setAntiAlias(true); const SkColor thumb_on_color = GetNativeTheme()->GetSystemColor( ui::NativeTheme::kColorId_ProminentButtonColor); const SkColor thumb_off_color = GetNativeTheme()->GetSystemColor( ui::NativeTheme::kColorId_DialogBackground); const SkAlpha blend = static_cast<SkAlpha>(SK_AlphaOPAQUE * color_ratio_); - thumb_paint.setColor( + thumb_flags.setColor( color_utils::AlphaBlend(thumb_on_color, thumb_off_color, blend)); // We want the circle to have an integer pixel diameter and to be aligned @@ -97,7 +97,7 @@ thumb_bounds.Scale(dsf); thumb_bounds = gfx::RectF(gfx::ToEnclosingRect(thumb_bounds)); canvas->DrawCircle(thumb_bounds.CenterPoint(), thumb_bounds.height() / 2.f, - thumb_paint); + thumb_flags); } // Color ratio between 0 and 1 that controls the thumb color. @@ -197,13 +197,13 @@ gfx::RectF track_rect(GetTrackBounds()); track_rect.Scale(dsf); track_rect = gfx::RectF(gfx::ToEnclosingRect(track_rect)); - cc::PaintFlags track_paint; - track_paint.setAntiAlias(true); + cc::PaintFlags track_flags; + track_flags.setAntiAlias(true); const double color_ratio = slide_animation_.GetCurrentValue(); - track_paint.setColor(color_utils::AlphaBlend( + track_flags.setColor(color_utils::AlphaBlend( GetTrackColor(true), GetTrackColor(false), static_cast<SkAlpha>(SK_AlphaOPAQUE * color_ratio))); - canvas->DrawRoundRect(track_rect, track_rect.height() / 2, track_paint); + canvas->DrawRoundRect(track_rect, track_rect.height() / 2, track_flags); canvas->Restore(); Painter::PaintFocusPainter(this, canvas, focus_painter_.get());
diff --git a/ui/views/controls/combobox/combobox.cc b/ui/views/controls/combobox/combobox.cc index 447e56f..abcb934 100644 --- a/ui/views/controls/combobox/combobox.cc +++ b/ui/views/controls/combobox/combobox.cc
@@ -857,14 +857,14 @@ path.rLineTo(2 * kEpsilon, 0); path.rLineTo(height, -height); path.close(); - cc::PaintFlags paint; + cc::PaintFlags flags; SkColor arrow_color = GetNativeTheme()->GetSystemColor( ui::NativeTheme::kColorId_ButtonEnabledColor); if (!enabled()) arrow_color = SkColorSetA(arrow_color, gfx::kDisabledControlAlpha); - paint.setColor(arrow_color); - paint.setAntiAlias(true); - canvas->DrawPath(path, paint); + flags.setColor(arrow_color); + flags.setAntiAlias(true); + canvas->DrawPath(path, flags); } else { canvas->DrawImageInt(arrow_image_, arrow_bounds.x(), arrow_bounds.y()); }
diff --git a/ui/views/controls/focus_ring.cc b/ui/views/controls/focus_ring.cc index c8c4d47..b905823 100644 --- a/ui/views/controls/focus_ring.cc +++ b/ui/views/controls/focus_ring.cc
@@ -69,19 +69,19 @@ } void FocusRing::OnPaint(gfx::Canvas* canvas) { - cc::PaintFlags paint; - paint.setAntiAlias(true); - paint.setColor( + cc::PaintFlags flags; + flags.setAntiAlias(true); + flags.setColor( SkColorSetA(GetNativeTheme()->GetSystemColor( override_color_id_ != ui::NativeTheme::kColorId_NumColors ? override_color_id_ : ui::NativeTheme::kColorId_FocusedBorderColor), 0x66)); - paint.setStyle(cc::PaintFlags::kStroke_Style); - paint.setStrokeWidth(kFocusHaloThicknessDp); + flags.setStyle(cc::PaintFlags::kStroke_Style); + flags.setStrokeWidth(kFocusHaloThicknessDp); gfx::RectF rect(GetLocalBounds()); rect.Inset(gfx::InsetsF(kFocusHaloThicknessDp / 2.f)); - canvas->DrawRoundRect(rect, kFocusHaloCornerRadiusDp, paint); + canvas->DrawRoundRect(rect, kFocusHaloCornerRadiusDp, flags); } FocusRing::FocusRing()
diff --git a/ui/views/controls/focusable_border.cc b/ui/views/controls/focusable_border.cc index 09d456d..a63629c0 100644 --- a/ui/views/controls/focusable_border.cc +++ b/ui/views/controls/focusable_border.cc
@@ -39,9 +39,9 @@ if (ui::MaterialDesignController::IsSecondaryUiMaterial() && view.HasFocus()) return; - cc::PaintFlags paint; - paint.setStyle(cc::PaintFlags::kStroke_Style); - paint.setColor(GetCurrentColor(view)); + cc::PaintFlags flags; + flags.setStyle(cc::PaintFlags::kStroke_Style); + flags.setColor(GetCurrentColor(view)); if (ui::MaterialDesignController::IsSecondaryUiMaterial()) { gfx::ScopedCanvas scoped(canvas); @@ -54,15 +54,15 @@ path.addRoundRect(gfx::RectFToSkRect(rect), corner_radius_px, corner_radius_px); const int kStrokeWidthPx = 1; - paint.setStrokeWidth(SkIntToScalar(kStrokeWidthPx)); - paint.setAntiAlias(true); - canvas->DrawPath(path, paint); + flags.setStrokeWidth(SkIntToScalar(kStrokeWidthPx)); + flags.setAntiAlias(true); + canvas->DrawPath(path, flags); } else { SkPath path; path.addRect(gfx::RectToSkRect(view.GetLocalBounds()), SkPath::kCW_Direction); - paint.setStrokeWidth(SkIntToScalar(2)); - canvas->DrawPath(path, paint); + flags.setStrokeWidth(SkIntToScalar(2)); + canvas->DrawPath(path, flags); } }
diff --git a/ui/views/controls/focusable_rounded_border_mac.cc b/ui/views/controls/focusable_rounded_border_mac.cc index 894aca9..ba19855 100644 --- a/ui/views/controls/focusable_rounded_border_mac.cc +++ b/ui/views/controls/focusable_rounded_border_mac.cc
@@ -28,17 +28,16 @@ // likely diverge in future. // TODO(ellyjones): Diverge it by adding soft focus rings. void FocusableRoundedBorder::Paint(const View& view, gfx::Canvas* canvas) { - cc::PaintFlags paint; - paint.setStyle(cc::PaintFlags::kStroke_Style); - paint.setStrokeWidth(kThickness); - paint.setColor(GetCurrentColor(view)); - paint.setAntiAlias(true); + cc::PaintFlags flags; + flags.setStyle(cc::PaintFlags::kStroke_Style); + flags.setStrokeWidth(kThickness); + flags.setColor(GetCurrentColor(view)); + flags.setAntiAlias(true); float half_thickness = kThickness / 2.0f; gfx::RectF bounds(view.GetLocalBounds()); bounds.Inset(half_thickness, half_thickness); - canvas->DrawRoundRect(bounds, ui::NativeThemeMac::kButtonCornerRadius, - paint); + canvas->DrawRoundRect(bounds, ui::NativeThemeMac::kButtonCornerRadius, flags); } } // namespace views
diff --git a/ui/views/controls/image_view.cc b/ui/views/controls/image_view.cc index 22f0f98e..edd639e 100644 --- a/ui/views/controls/image_view.cc +++ b/ui/views/controls/image_view.cc
@@ -221,11 +221,12 @@ if (image_bounds.size() != gfx::Size(image_.width(), image_.height())) { // Resize case - cc::PaintFlags paint; - paint.setFilterQuality(kLow_SkFilterQuality); + cc::PaintFlags flags; + flags.setFilterQuality(kLow_SkFilterQuality); canvas->DrawImageInt(image_, 0, 0, image_.width(), image_.height(), - image_bounds.x(), image_bounds.y(), image_bounds.width(), - image_bounds.height(), true, paint); + image_bounds.x(), image_bounds.y(), + image_bounds.width(), image_bounds.height(), true, + flags); } else { canvas->DrawImageInt(image_, image_bounds.x(), image_bounds.y()); }
diff --git a/ui/views/controls/md_slider.cc b/ui/views/controls/md_slider.cc index 8e1870c..64bed2fa 100644 --- a/ui/views/controls/md_slider.cc +++ b/ui/views/controls/md_slider.cc
@@ -60,16 +60,16 @@ // Extra space used to hide slider ends behind the thumb. const int extra_padding = 1; - cc::PaintFlags slider_paint; - slider_paint.setAntiAlias(true); - slider_paint.setColor(current_thumb_color); + cc::PaintFlags slider_flags; + slider_flags.setAntiAlias(true); + slider_flags.setColor(current_thumb_color); canvas->DrawRoundRect( gfx::Rect(content.x(), y, full + extra_padding, kLineThickness), - kSliderRoundedRadius, slider_paint); - slider_paint.setColor(kDisabledColor); + kSliderRoundedRadius, slider_flags); + slider_flags.setColor(kDisabledColor); canvas->DrawRoundRect(gfx::Rect(x + kThumbRadius - extra_padding, y, empty + extra_padding, kLineThickness), - kSliderRoundedRadius, slider_paint); + kSliderRoundedRadius, slider_flags); gfx::Point thumb_center(x, content.height() / 2); @@ -85,17 +85,17 @@ } // Paint the thumb of the slider. - cc::PaintFlags paint; - paint.setColor(current_thumb_color); - paint.setFlags(cc::PaintFlags::kAntiAlias_Flag); + cc::PaintFlags flags; + flags.setColor(current_thumb_color); + flags.setFlags(cc::PaintFlags::kAntiAlias_Flag); if (!is_active_) { - paint.setStrokeWidth(kThumbStroke); - paint.setStyle(cc::PaintFlags::kStroke_Style); + flags.setStrokeWidth(kThumbStroke); + flags.setStyle(cc::PaintFlags::kStroke_Style); } canvas->DrawCircle( thumb_center, - is_active_ ? kThumbRadius : (kThumbRadius - kThumbStroke / 2), paint); + is_active_ ? kThumbRadius : (kThumbRadius - kThumbStroke / 2), flags); } const char* MdSlider::GetClassName() const {
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc index 2accca9..4183b1a0 100644 --- a/ui/views/controls/menu/menu_controller.cc +++ b/ui/views/controls/menu/menu_controller.cc
@@ -515,7 +515,8 @@ if (!showing_) { // This occurs if we're in the process of notifying the delegate for a drop - // and the delegate cancels us. + // and the delegate cancels us. Or if the releasing of ViewsDelegate causes + // an immediate shutdown. return; } @@ -544,18 +545,21 @@ return; } + // If |type| is EXIT_ALL we update the state of the menu to not showing. For + // dragging this ensures that the correct visual state is reported until the + // drag operation completes. For non-dragging cases it is possible that the + // release of ViewsDelegate leads immediately to shutdown, which can trigger + // nested calls to Cancel. We want to reject these to prevent attempting a + // nested tear down of this and |delegate_|. + if (type == EXIT_ALL) + showing_ = false; + // On Windows and Linux the destruction of this menu's Widget leads to the // teardown of the platform specific drag-and-drop Widget. Do not shutdown // while dragging, leave the Widget hidden until drag-and-drop has completed, // at which point all menus will be destroyed. - // - // If |type| is EXIT_ALL we update the state of the menu to not showing. So - // that during the completion of a drag we are not incorrectly reporting the - // visual state. if (!drag_in_progress_) ExitAsyncRun(); - else if (type == EXIT_ALL) - showing_ = false; } void MenuController::AddNestedDelegate(
diff --git a/ui/views/controls/menu/menu_runner_impl.h b/ui/views/controls/menu/menu_runner_impl.h index 8312f42..83c4723 100644 --- a/ui/views/controls/menu/menu_runner_impl.h +++ b/ui/views/controls/menu/menu_runner_impl.h
@@ -23,6 +23,12 @@ class MenuDelegate; class MenuItemView; +namespace test { + +class MenuRunnerDestructionTest; + +} // namespace test + namespace internal { // A menu runner implementation that uses views::MenuItemView to show a menu. @@ -49,6 +55,8 @@ void SiblingMenuCreated(MenuItemView* menu) override; private: + friend class ::views::test::MenuRunnerDestructionTest; + ~MenuRunnerImpl() override; // Cleans up after the menu is no longer showing. |result| is the menu that
diff --git a/ui/views/controls/menu/menu_runner_unittest.cc b/ui/views/controls/menu/menu_runner_unittest.cc index 7b0503f5..4a96bdb 100644 --- a/ui/views/controls/menu/menu_runner_unittest.cc +++ b/ui/views/controls/menu/menu_runner_unittest.cc
@@ -21,10 +21,41 @@ #include "ui/views/controls/menu/submenu_view.h" #include "ui/views/test/menu_test_utils.h" #include "ui/views/test/test_views.h" +#include "ui/views/test/test_views_delegate.h" #include "ui/views/test/views_test_base.h" #include "ui/views/widget/native_widget_private.h" #include "ui/views/widget/widget.h" +namespace { + +// Accepts a MenuRunnerImpl to release when this is. Simulates shutdown +// occurring immediately during the release of ViewsDelegate. +class DeletingTestViewsDelegate : public views::TestViewsDelegate { + public: + DeletingTestViewsDelegate() : menu_runner_(nullptr) {} + ~DeletingTestViewsDelegate() override{}; + + void set_menu_runner(views::internal::MenuRunnerImpl* menu_runner) { + menu_runner_ = menu_runner; + } + + // views::ViewsDelegate: + void ReleaseRef() override; + + private: + // Not owned, deletes itself. + views::internal::MenuRunnerImpl* menu_runner_; + + DISALLOW_COPY_AND_ASSIGN(DeletingTestViewsDelegate); +}; + +void DeletingTestViewsDelegate::ReleaseRef() { + if (menu_runner_) + menu_runner_->Release(); +} + +} // namespace + namespace views { namespace test { @@ -420,5 +451,62 @@ EXPECT_EQ(nullptr, menu_controller.controller()); } +// Test class which overrides the ViewsDelegate. Allowing to simulate shutdown +// during its release. +class MenuRunnerDestructionTest : public MenuRunnerTest { + public: + MenuRunnerDestructionTest() {} + ~MenuRunnerDestructionTest() override {} + + DeletingTestViewsDelegate* views_delegate() { return views_delegate_; } + + base::WeakPtr<internal::MenuRunnerImpl> MenuRunnerAsWeakPtr( + internal::MenuRunnerImpl* menu_runner); + + // ViewsTestBase: + void SetUp() override; + + private: + // Not owned + DeletingTestViewsDelegate* views_delegate_; + + DISALLOW_COPY_AND_ASSIGN(MenuRunnerDestructionTest); +}; + +base::WeakPtr<internal::MenuRunnerImpl> +MenuRunnerDestructionTest::MenuRunnerAsWeakPtr( + internal::MenuRunnerImpl* menu_runner) { + return menu_runner->weak_factory_.GetWeakPtr(); +} + +void MenuRunnerDestructionTest::SetUp() { + std::unique_ptr<DeletingTestViewsDelegate> views_delegate( + new DeletingTestViewsDelegate); + views_delegate_ = views_delegate.get(); + set_views_delegate(std::move(views_delegate)); + MenuRunnerTest::SetUp(); +} + +// Tests that when ViewsDelegate is released that a nested Cancel of the +// MenuRunner does not occur. +TEST_F(MenuRunnerDestructionTest, MenuRunnerDestroyedDuringReleaseRef) { + internal::MenuRunnerImpl* menu_runner = + new internal::MenuRunnerImpl(menu_item_view()); + EXPECT_EQ(MenuRunner::NORMAL_EXIT, + menu_runner->RunMenuAt(owner(), nullptr, gfx::Rect(), + MENU_ANCHOR_TOPLEFT, MenuRunner::ASYNC)); + + views_delegate()->set_menu_runner(menu_runner); + + base::WeakPtr<internal::MenuRunnerImpl> ref(MenuRunnerAsWeakPtr(menu_runner)); + MenuControllerTestApi menu_controller; + // This will release the ref on ViewsDelegate. The test version will release + // |menu_runner| simulating device shutdown. + menu_controller.controller()->CancelAll(); + // Both the |menu_runner| and |menu_controller| should have been deleted. + EXPECT_EQ(nullptr, ref); + EXPECT_EQ(nullptr, menu_controller.controller()); +} + } // namespace test } // namespace views
diff --git a/ui/views/controls/menu/menu_scroll_view_container.cc b/ui/views/controls/menu/menu_scroll_view_container.cc index 17bd782..124442a 100644 --- a/ui/views/controls/menu/menu_scroll_view_container.cc +++ b/ui/views/controls/menu/menu_scroll_view_container.cc
@@ -101,11 +101,11 @@ path.lineTo(SkIntToScalar(x_left), SkIntToScalar(y_bottom)); path.lineTo(SkIntToScalar(x_right), SkIntToScalar(y_bottom)); path.lineTo(SkIntToScalar(x), SkIntToScalar(y)); - cc::PaintFlags paint; - paint.setStyle(cc::PaintFlags::kFill_Style); - paint.setAntiAlias(true); - paint.setColor(config.arrow_color); - canvas->DrawPath(path, paint); + cc::PaintFlags flags; + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setAntiAlias(true); + flags.setColor(config.arrow_color); + canvas->DrawPath(path, flags); } private:
diff --git a/ui/views/controls/progress_bar.cc b/ui/views/controls/progress_bar.cc index f6d14ab7..c624fed 100644 --- a/ui/views/controls/progress_bar.cc +++ b/ui/views/controls/progress_bar.cc
@@ -76,11 +76,11 @@ // Draw background. SkPath background_path; AddPossiblyRoundRectToPath(content_bounds, &background_path); - cc::PaintFlags background_paint; - background_paint.setStyle(cc::PaintFlags::kFill_Style); - background_paint.setAntiAlias(true); - background_paint.setColor(GetBackgroundColor()); - canvas->DrawPath(background_path, background_paint); + cc::PaintFlags background_flags; + background_flags.setStyle(cc::PaintFlags::kFill_Style); + background_flags.setAntiAlias(true); + background_flags.setColor(GetBackgroundColor()); + canvas->DrawPath(background_path, background_flags); // Draw slice. SkPath slice_path; @@ -93,11 +93,11 @@ slice_bounds.set_width(slice_width); AddPossiblyRoundRectToPath(slice_bounds, &slice_path); - cc::PaintFlags slice_paint; - slice_paint.setStyle(cc::PaintFlags::kFill_Style); - slice_paint.setAntiAlias(true); - slice_paint.setColor(GetForegroundColor()); - canvas->DrawPath(slice_path, slice_paint); + cc::PaintFlags slice_flags; + slice_flags.setStyle(cc::PaintFlags::kFill_Style); + slice_flags.setAntiAlias(true); + slice_flags.setColor(GetForegroundColor()); + canvas->DrawPath(slice_path, slice_flags); } void ProgressBar::SetValue(double value) { @@ -151,11 +151,11 @@ // Draw background. SkPath background_path; AddPossiblyRoundRectToPath(content_bounds, &background_path); - cc::PaintFlags background_paint; - background_paint.setStyle(cc::PaintFlags::kFill_Style); - background_paint.setAntiAlias(true); - background_paint.setColor(GetBackgroundColor()); - canvas->DrawPath(background_path, background_paint); + cc::PaintFlags background_flags; + background_flags.setStyle(cc::PaintFlags::kFill_Style); + background_flags.setAntiAlias(true); + background_flags.setColor(GetBackgroundColor()); + canvas->DrawPath(background_path, background_flags); // Draw slice. SkPath slice_path; @@ -199,11 +199,11 @@ slice_bounds.set_width(bar2_end_x - bar2_start_x); AddPossiblyRoundRectToPath(slice_bounds, &slice_path); - cc::PaintFlags slice_paint; - slice_paint.setStyle(cc::PaintFlags::kFill_Style); - slice_paint.setAntiAlias(true); - slice_paint.setColor(GetForegroundColor()); - canvas->DrawPath(slice_path, slice_paint); + cc::PaintFlags slice_flags; + slice_flags.setStyle(cc::PaintFlags::kFill_Style); + slice_flags.setAntiAlias(true); + slice_flags.setColor(GetForegroundColor()); + canvas->DrawPath(slice_path, slice_flags); } } // namespace views
diff --git a/ui/views/controls/scrollbar/cocoa_scroll_bar.mm b/ui/views/controls/scrollbar/cocoa_scroll_bar.mm index bc3c30f..c77bdf4 100644 --- a/ui/views/controls/scrollbar/cocoa_scroll_bar.mm +++ b/ui/views/controls/scrollbar/cocoa_scroll_bar.mm
@@ -122,13 +122,13 @@ } gfx::Rect local_bounds(GetLocalBounds()); - cc::PaintFlags paint; - paint.setAntiAlias(true); - paint.setStyle(cc::PaintFlags::kFill_Style); - paint.setColor(thumb_color); + cc::PaintFlags flags; + flags.setAntiAlias(true); + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setColor(thumb_color); const SkScalar radius = std::min(local_bounds.width(), local_bounds.height()); - canvas->DrawRoundRect(local_bounds, radius, paint); + canvas->DrawRoundRect(local_bounds, radius, flags); } bool CocoaScrollBarThumb::OnMousePressed(const ui::MouseEvent& event) { @@ -263,23 +263,23 @@ canvas->DrawRect(track_rect, gradient); // Draw the inner border: top if horizontal, left if vertical. - cc::PaintFlags paint; - paint.setColor(kScrollerTrackInnerBorderColor); + cc::PaintFlags flags; + flags.setColor(kScrollerTrackInnerBorderColor); gfx::Rect inner_border(track_rect); if (IsHorizontal()) inner_border.set_height(kScrollerTrackBorderWidth); else inner_border.set_width(kScrollerTrackBorderWidth); - canvas->DrawRect(inner_border, paint); + canvas->DrawRect(inner_border, flags); // Draw the outer border: bottom if horizontal, right if veritcal. - paint.setColor(kScrollerTrackOuterBorderColor); + flags.setColor(kScrollerTrackOuterBorderColor); gfx::Rect outer_border(inner_border); if (IsHorizontal()) outer_border.set_y(track_rect.bottom()); else outer_border.set_x(track_rect.right()); - canvas->DrawRect(outer_border, paint); + canvas->DrawRect(outer_border, flags); } bool CocoaScrollBar::OnMousePressed(const ui::MouseEvent& event) {
diff --git a/ui/views/controls/scrollbar/overlay_scroll_bar.cc b/ui/views/controls/scrollbar/overlay_scroll_bar.cc index 4565221c..4c0a6d5 100644 --- a/ui/views/controls/scrollbar/overlay_scroll_bar.cc +++ b/ui/views/controls/scrollbar/overlay_scroll_bar.cc
@@ -52,21 +52,21 @@ } void OverlayScrollBar::Thumb::OnPaint(gfx::Canvas* canvas) { - cc::PaintFlags fill_paint; - fill_paint.setStyle(cc::PaintFlags::kFill_Style); - fill_paint.setColor(SK_ColorBLACK); + cc::PaintFlags fill_flags; + fill_flags.setStyle(cc::PaintFlags::kFill_Style); + fill_flags.setColor(SK_ColorBLACK); gfx::RectF fill_bounds(GetLocalBounds()); fill_bounds.Inset(gfx::InsetsF(IsHorizontal() ? kThumbHoverOffset : 0, IsHorizontal() ? 0 : kThumbHoverOffset, 0, 0)); fill_bounds.Inset(gfx::InsetsF(kThumbStroke, kThumbStroke, IsHorizontal() ? 0 : kThumbStroke, IsHorizontal() ? kThumbStroke : 0)); - canvas->DrawRect(fill_bounds, fill_paint); + canvas->DrawRect(fill_bounds, fill_flags); - cc::PaintFlags stroke_paint; - stroke_paint.setStyle(cc::PaintFlags::kStroke_Style); - stroke_paint.setColor(SK_ColorWHITE); - stroke_paint.setStrokeWidth(kThumbStroke); + cc::PaintFlags stroke_flags; + stroke_flags.setStyle(cc::PaintFlags::kStroke_Style); + stroke_flags.setColor(SK_ColorWHITE); + stroke_flags.setStrokeWidth(kThumbStroke); gfx::RectF stroke_bounds(fill_bounds); stroke_bounds.Inset(gfx::InsetsF(kThumbStroke / 2.f)); // The stroke doesn't apply to the far edge of the thumb. @@ -80,7 +80,7 @@ } else { path.lineTo(gfx::PointFToSkPoint(stroke_bounds.bottom_right())); } - canvas->DrawPath(path, stroke_paint); + canvas->DrawPath(path, stroke_flags); } void OverlayScrollBar::Thumb::OnBoundsChanged(
diff --git a/ui/views/controls/tabbed_pane/tabbed_pane.cc b/ui/views/controls/tabbed_pane/tabbed_pane.cc index fd30e6b..8a8c753 100644 --- a/ui/views/controls/tabbed_pane/tabbed_pane.cc +++ b/ui/views/controls/tabbed_pane/tabbed_pane.cc
@@ -340,9 +340,9 @@ } void TabStrip::OnPaintBorder(gfx::Canvas* canvas) { - cc::PaintFlags paint; - paint.setColor(kTabBorderColor); - paint.setStrokeWidth(kTabBorderThickness); + cc::PaintFlags fill_flags; + fill_flags.setColor(kTabBorderColor); + fill_flags.setStrokeWidth(kTabBorderThickness); SkScalar line_y = SkIntToScalar(height()) - (kTabBorderThickness / 2); SkScalar line_end = SkIntToScalar(width()); int selected_tab_index = GetSelectedTabIndex(); @@ -361,13 +361,13 @@ path.rLineTo(0, tab_height); path.lineTo(line_end, line_y); - cc::PaintFlags paint; - paint.setStyle(cc::PaintFlags::kStroke_Style); - paint.setColor(kTabBorderColor); - paint.setStrokeWidth(kTabBorderThickness); - canvas->DrawPath(path, paint); + cc::PaintFlags fill_flags; + fill_flags.setStyle(cc::PaintFlags::kStroke_Style); + fill_flags.setColor(kTabBorderColor); + fill_flags.setStrokeWidth(kTabBorderThickness); + canvas->DrawPath(path, fill_flags); } else { - canvas->sk_canvas()->drawLine(0, line_y, line_end, line_y, paint); + canvas->sk_canvas()->drawLine(0, line_y, line_end, line_y, fill_flags); } }
diff --git a/ui/views/controls/table/table_header.cc b/ui/views/controls/table/table_header.cc index d704efe8..658079d 100644 --- a/ui/views/controls/table/table_header.cc +++ b/ui/views/controls/table/table_header.cc
@@ -105,10 +105,10 @@ TableColumnAlignmentToCanvasAlignment(columns[i].column.alignment)); if (paint_sort_indicator) { - cc::PaintFlags paint; - paint.setColor(text_color); - paint.setStyle(cc::PaintFlags::kFill_Style); - paint.setAntiAlias(true); + cc::PaintFlags flags; + flags.setColor(text_color); + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setAntiAlias(true); int indicator_x = 0; ui::TableColumn::Alignment alignment = columns[i].column.alignment; @@ -156,7 +156,7 @@ SkIntToScalar(indicator_y + kSortIndicatorSize)); } indicator_path.close(); - canvas->DrawPath(indicator_path, paint); + canvas->DrawPath(indicator_path, flags); } } }
diff --git a/ui/views/controls/table/table_view.cc b/ui/views/controls/table/table_view.cc index e849df4..db200b5 100644 --- a/ui/views/controls/table/table_view.cc +++ b/ui/views/controls/table/table_view.cc
@@ -600,10 +600,10 @@ const SkColor grouping_color = GetNativeTheme()->GetSystemColor( ui::NativeTheme::kColorId_TableGroupingIndicatorColor); - cc::PaintFlags grouping_paint; - grouping_paint.setColor(grouping_color); - grouping_paint.setStyle(cc::PaintFlags::kFill_Style); - grouping_paint.setAntiAlias(true); + cc::PaintFlags grouping_flags; + grouping_flags.setColor(grouping_color); + grouping_flags.setStyle(cc::PaintFlags::kFill_Style); + grouping_flags.setAntiAlias(true); const int group_indicator_x = GetMirroredXInView(GetCellBounds(0, 0).x() + kTextHorizontalPadding + kGroupingIndicatorSize / 2); for (int i = region.min_row; i < region.max_row; ) { @@ -624,13 +624,13 @@ kGroupingIndicatorSize, last_cell_bounds.y() - start_cell_bounds.y()), grouping_color); - canvas->DrawCircle(gfx::Point(group_indicator_x, - last_cell_bounds.CenterPoint().y()), - kGroupingIndicatorSize / 2, grouping_paint); + canvas->DrawCircle( + gfx::Point(group_indicator_x, last_cell_bounds.CenterPoint().y()), + kGroupingIndicatorSize / 2, grouping_flags); } - canvas->DrawCircle(gfx::Point(group_indicator_x, - start_cell_bounds.CenterPoint().y()), - kGroupingIndicatorSize / 2, grouping_paint); + canvas->DrawCircle( + gfx::Point(group_indicator_x, start_cell_bounds.CenterPoint().y()), + kGroupingIndicatorSize / 2, grouping_flags); i = last + 1; } }
diff --git a/ui/views/layout/layout_constants.h b/ui/views/layout/layout_constants.h index 798a440..a0ab3f1a 100644 --- a/ui/views/layout/layout_constants.h +++ b/ui/views/layout/layout_constants.h
@@ -70,6 +70,9 @@ // left or right of a button (when using new style dialogs). constexpr int kButtonHEdgeMarginNew = 20; +// Spacing between the edge of the window and the edge of the close button. +const int kCloseButtonMargin = 7; + // Horizontal spacing between buttons that are logically related. constexpr int kRelatedButtonHSpacing = 6;
diff --git a/ui/views/mus/mus_client.h b/ui/views/mus/mus_client.h index d43579b..3e881c5d 100644 --- a/ui/views/mus/mus_client.h +++ b/ui/views/mus/mus_client.h
@@ -12,6 +12,7 @@ #include <vector> #include "base/macros.h" +#include "services/service_manager/public/cpp/identity.h" #include "ui/aura/client/capture_client.h" #include "ui/aura/mus/window_tree_client_delegate.h" #include "ui/base/dragdrop/os_exchange_data_provider_factory.h" @@ -36,7 +37,6 @@ namespace service_manager { class Connector; -class Identity; } namespace wm {
diff --git a/ui/views/painter.cc b/ui/views/painter.cc index e6384db..655abd82 100644 --- a/ui/views/painter.cc +++ b/ui/views/painter.cc
@@ -70,17 +70,17 @@ gfx::RectF border_rect_f(gfx::ScaleToEnclosingRect(gfx::Rect(size), scale)); const SkScalar scaled_corner_radius = SkFloatToScalar(radius_ * scale); - cc::PaintFlags paint; - paint.setAntiAlias(true); - paint.setStyle(cc::PaintFlags::kFill_Style); - paint.setColor(bg_color_); - canvas->DrawRoundRect(border_rect_f, scaled_corner_radius, paint); + cc::PaintFlags flags; + flags.setAntiAlias(true); + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setColor(bg_color_); + canvas->DrawRoundRect(border_rect_f, scaled_corner_radius, flags); border_rect_f.Inset(gfx::InsetsF(0.5f)); - paint.setStyle(cc::PaintFlags::kStroke_Style); - paint.setStrokeWidth(1); - paint.setColor(stroke_color_); - canvas->DrawRoundRect(border_rect_f, scaled_corner_radius, paint); + flags.setStyle(cc::PaintFlags::kStroke_Style); + flags.setStrokeWidth(1); + flags.setColor(stroke_color_); + canvas->DrawRoundRect(border_rect_f, scaled_corner_radius, flags); } // DashedFocusPainter ---------------------------------------------------------- @@ -205,7 +205,7 @@ } void GradientPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) { - cc::PaintFlags paint; + cc::PaintFlags flags; SkPoint p[2]; p[0].iset(0, 0); if (horizontal_) @@ -213,13 +213,13 @@ else p[1].iset(0, size.height()); - paint.setShader(cc::WrapSkShader(SkGradientShader::MakeLinear( + flags.setShader(cc::WrapSkShader(SkGradientShader::MakeLinear( p, colors_.get(), pos_.get(), count_, SkShader::kClamp_TileMode))); - paint.setStyle(cc::PaintFlags::kFill_Style); + flags.setStyle(cc::PaintFlags::kFill_Style); canvas->sk_canvas()->drawRectCoords(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(size.width()), - SkIntToScalar(size.height()), paint); + SkIntToScalar(size.height()), flags); } // ImagePainter ---------------------------------------------------------------
diff --git a/ui/views/round_rect_painter.cc b/ui/views/round_rect_painter.cc index 20869c7f..058cc97 100644 --- a/ui/views/round_rect_painter.cc +++ b/ui/views/round_rect_painter.cc
@@ -24,17 +24,17 @@ } void RoundRectPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) { - cc::PaintFlags paint; - paint.setColor(border_color_); - paint.setStyle(cc::PaintFlags::kStroke_Style); - paint.setStrokeWidth(kBorderWidth); - paint.setAntiAlias(true); + cc::PaintFlags flags; + flags.setColor(border_color_); + flags.setStyle(cc::PaintFlags::kStroke_Style); + flags.setStrokeWidth(kBorderWidth); + flags.setAntiAlias(true); gfx::Rect rect(size); rect.Inset(0, 0, kBorderWidth, kBorderWidth); SkRect skia_rect = gfx::RectToSkRect(rect); skia_rect.offset(kBorderWidth / 2.f, kBorderWidth / 2.f); canvas->sk_canvas()->drawRoundRect(skia_rect, SkIntToScalar(corner_radius_), - SkIntToScalar(corner_radius_), paint); + SkIntToScalar(corner_radius_), flags); } } // namespace views
diff --git a/ui/views/shadow_border.cc b/ui/views/shadow_border.cc index 50e143a..e10c447 100644 --- a/ui/views/shadow_border.cc +++ b/ui/views/shadow_border.cc
@@ -35,15 +35,15 @@ // TODO(sidharthms): Re-painting a shadow looper on every paint call may yield // poor performance. Ideally we should be caching the border to bitmaps. void ShadowBorder::Paint(const views::View& view, gfx::Canvas* canvas) { - cc::PaintFlags paint; + cc::PaintFlags flags; std::vector<gfx::ShadowValue> shadows; shadows.push_back(shadow_value_); - paint.setLooper(gfx::CreateShadowDrawLooper(shadows)); - paint.setColor(SK_ColorTRANSPARENT); - paint.setStrokeJoin(cc::PaintFlags::kRound_Join); + flags.setLooper(gfx::CreateShadowDrawLooper(shadows)); + flags.setColor(SK_ColorTRANSPARENT); + flags.setStrokeJoin(cc::PaintFlags::kRound_Join); gfx::Rect bounds(view.size()); bounds.Inset(-gfx::ShadowValue::GetMargin(shadows)); - canvas->DrawRect(bounds, paint); + canvas->DrawRect(bounds, flags); } gfx::Insets ShadowBorder::GetInsets() const {
diff --git a/ui/views/views_delegate.cc b/ui/views/views_delegate.cc index e7fa2be..c47604b 100644 --- a/ui/views/views_delegate.cc +++ b/ui/views/views_delegate.cc
@@ -131,6 +131,10 @@ kButtonHEdgeMarginNew); } +int ViewsDelegate::GetDialogCloseButtonMargin() const { + return kCloseButtonMargin; +} + int ViewsDelegate::GetDialogRelatedButtonHorizontalSpacing() const { return kRelatedButtonHSpacing; }
diff --git a/ui/views/views_delegate.h b/ui/views/views_delegate.h index cbe34562..c347519 100644 --- a/ui/views/views_delegate.h +++ b/ui/views/views_delegate.h
@@ -201,6 +201,10 @@ // DialogClientView's content view. virtual gfx::Insets GetDialogButtonInsets() const; + // Returns the distance between a dialog's edge and the close button in the + // upper trailing corner. + virtual int GetDialogCloseButtonMargin() const; + // Returns the spacing between a pair of related horizontal buttons, used for // dialog layout. virtual int GetDialogRelatedButtonHorizontalSpacing() const;
diff --git a/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html b/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html index 9ffd7ea2..3d4ce17 100644 --- a/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html +++ b/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html
@@ -87,7 +87,7 @@ border-bottom-left-radius: inherit; border-bottom-right-radius: inherit; margin: 0; - padding: 12px 20px; + padding: 16px 20px; } :host ::content .border-top-divider {
diff --git a/ui/webui/resources/cr_elements/network/cr_network_icon.html b/ui/webui/resources/cr_elements/network/cr_network_icon.html index 27875ca5..1c4b3f7b 100644 --- a/ui/webui/resources/cr_elements/network/cr_network_icon.html +++ b/ui/webui/resources/cr_elements/network/cr_network_icon.html
@@ -8,6 +8,7 @@ <style> :host { display: inline-flex; + opacity: .65; /* Equivalent to #5a5a5a */ overflow: hidden; padding: 2px; position: relative;
diff --git a/ui/webui/resources/cr_elements/network/cr_network_list.html b/ui/webui/resources/cr_elements/network/cr_network_list.html index 2f0ac3a..daacb95 100644 --- a/ui/webui/resources/cr_elements/network/cr_network_list.html +++ b/ui/webui/resources/cr_elements/network/cr_network_list.html
@@ -11,13 +11,25 @@ :host { display: inline-flex; } + #container { max-height: 1000px; min-height: 50px; overflow-y: auto; } + + /* Override scrollable border-bottom-color */ + #container[no-bottom-scroll-border] { + border-bottom-color: transparent; + } + + iron-list > *:not(:first-of-type) { + border-top: var(--cr-separator-line); + } + </style> - <div id="container" class="layout vertical flex" scrollable> + <div id="container" class="layout vertical flex" scrollable + no-bottom-scroll-border$="[[noBottomScrollBorder]]"> <iron-list id="networkList" selection-enabled items="[[listItems_]]" scroll-target="container" selected-item="{{selectedItem}}"> <template>
diff --git a/ui/webui/resources/cr_elements/network/cr_network_list.js b/ui/webui/resources/cr_elements/network/cr_network_list.js index 8dcce41d..82b5fc7 100644 --- a/ui/webui/resources/cr_elements/network/cr_network_list.js +++ b/ui/webui/resources/cr_elements/network/cr_network_list.js
@@ -70,12 +70,7 @@ /** @private */ updateListItems_: function() { this.saveScroll(this.$.networkList); - - var customItems = this.customItems.slice(); - if (customItems.length > 0) - customItems[0].isFirstCustomItem = true; - this.listItems_ = this.networks.concat(customItems); - + this.listItems_ = this.networks.concat(this.customItems); this.restoreScroll(this.$.networkList); this.updateScrollableContents(); },
diff --git a/ui/webui/resources/cr_elements/network/cr_network_list_item.html b/ui/webui/resources/cr_elements/network/cr_network_list_item.html index 88a6d9c..de555d0 100644 --- a/ui/webui/resources/cr_elements/network/cr_network_list_item.html +++ b/ui/webui/resources/cr_elements/network/cr_network_list_item.html
@@ -34,10 +34,6 @@ height: 32px; } - #divOuter[first-custom-item] { - border-top: var(--cr-separator-line); - } - #divText { -webkit-padding-end: 8px; display: flex; @@ -80,8 +76,7 @@ padding: 0 var(--cr-icon-padding); } </style> - <div id="divOuter" actionable$="[[isListItem]]" - first-custom-item$="[[item.isFirstCustomItem]]"> + <div id="divOuter" actionable$="[[isListItem]]"> <template is="dom-if" if="[[networkState]]"> <cr-network-icon is-list-item="[[isListItem]]" network-state="[[networkState]]">
diff --git a/ui/webui/resources/cr_elements/network/cr_network_list_types.js b/ui/webui/resources/cr_elements/network/cr_network_list_types.js index d3e707d..13a81dd 100644 --- a/ui/webui/resources/cr_elements/network/cr_network_list_types.js +++ b/ui/webui/resources/cr_elements/network/cr_network_list_types.js
@@ -17,7 +17,6 @@ * customItemName: string, * polymerIcon: (string|undefined), * customData: (!Object|undefined), - * isFirstCustomItem: (boolean|undefined), * }} */ CrNetworkList.CustomItemState;
diff --git a/ui/webui/resources/cr_elements/network/cr_network_select.html b/ui/webui/resources/cr_elements/network/cr_network_select.html index 0fc25d8..3bd7169 100644 --- a/ui/webui/resources/cr_elements/network/cr_network_select.html +++ b/ui/webui/resources/cr_elements/network/cr_network_select.html
@@ -11,8 +11,10 @@ } </style> <cr-network-list class ="flex" on-selected="onNetworkListItemSelected_" + on-network-connected="onNetworkConnected_" networks="[[networkStateList_]]" custom-items="[[customItems]]" - show-buttons="[[showButtons]]"> + show-buttons="[[showButtons]]" + no-bottom-scroll-border="[[noBottomScrollBorder]]"> </cr-network-list> </template> <script src="cr_network_select.js"></script>
diff --git a/ui/webui/resources/cr_elements/network/cr_network_select.js b/ui/webui/resources/cr_elements/network/cr_network_select.js index 6e925b1..6401ac4 100644 --- a/ui/webui/resources/cr_elements/network/cr_network_select.js +++ b/ui/webui/resources/cr_elements/network/cr_network_select.js
@@ -52,7 +52,7 @@ type: Array, value: function() { return []; - } + }, }, }, @@ -97,7 +97,6 @@ /** * Request the list of visible networks. May be called externally to force a * refresh and list update (e.g. when the element is shown). - * @private */ refreshNetworks: function() { var filter = { @@ -115,6 +114,12 @@ */ getNetworksCallback_: function(states) { this.networkStateList_ = states; + var defaultState = (this.networkStateList_.length > 0 && + this.networkStateList_[0].ConnectionState == + CrOnc.ConnectionState.CONNECTED) ? + this.networkStateList_[0] : + null; + this.defaultNetworkChanged_(defaultState); }, /** @@ -140,4 +145,21 @@ console.error('networkingPrivate.startConnect error: ' + lastError); }); }, + + /** + * Event triggered when a cr-network-list-item becomes connected. + * @param {!{target: HTMLElement, detail: !CrOnc.NetworkStateProperties}} e + * @private + */ + onNetworkConnected_: function(e) { + this.defaultNetworkChanged_(e.detail); + }, + + /** + * @param {?CrOnc.NetworkStateProperties} state + * @private + */ + defaultNetworkChanged_: function(state) { + this.fire('default-network-changed', state); + }, });
diff --git a/url/url_util.cc b/url/url_util.cc index d5c27d1..5daab04f 100644 --- a/url/url_util.cc +++ b/url/url_util.cc
@@ -73,6 +73,15 @@ kDataScheme, }; +const char* kWebStorageSchemes[] = { + kHttpScheme, + kHttpsScheme, + kFileScheme, + kFtpScheme, + kWsScheme, + kWssScheme, +}; + bool initialized = false; // Lists of the currently installed standard and referrer schemes. These lists @@ -86,6 +95,7 @@ std::vector<std::string>* local_schemes = nullptr; std::vector<std::string>* no_access_schemes = nullptr; std::vector<std::string>* cors_enabled_schemes = nullptr; +std::vector<std::string>* web_storage_schemes = nullptr; // See the LockSchemeRegistries declaration in the header. bool scheme_registries_locked = false; @@ -512,6 +522,8 @@ arraysize(kNoAccessSchemes)); InitSchemes(&cors_enabled_schemes, kCORSEnabledSchemes, arraysize(kCORSEnabledSchemes)); + InitSchemes(&web_storage_schemes, kWebStorageSchemes, + arraysize(kWebStorageSchemes)); initialized = true; } @@ -529,6 +541,8 @@ no_access_schemes = nullptr; delete cors_enabled_schemes; cors_enabled_schemes = nullptr; + delete web_storage_schemes; + web_storage_schemes = nullptr; } void AddStandardScheme(const char* new_scheme, SchemeType type) { @@ -581,6 +595,16 @@ return *cors_enabled_schemes; } +void AddWebStorageScheme(const char* new_scheme) { + Initialize(); + DoAddScheme(new_scheme, web_storage_schemes); +} + +const std::vector<std::string>& GetWebStorageSchemes() { + Initialize(); + return *web_storage_schemes; +} + void LockSchemeRegistries() { scheme_registries_locked = true; }
diff --git a/url/url_util.h b/url/url_util.h index e424c503..8cbb14c 100644 --- a/url/url_util.h +++ b/url/url_util.h
@@ -98,6 +98,14 @@ URL_EXPORT void AddCORSEnabledScheme(const char* new_scheme); URL_EXPORT const std::vector<std::string>& GetCORSEnabledSchemes(); +// Adds an application-defined scheme to the list of web schemes that can be +// used by web to store data (e.g. cookies, local storage, ...). This is +// to differentiate them from schemes that can store data but are not used on +// web (e.g. application's internal schemes) or schemes that are used on web but +// cannot store data. +URL_EXPORT void AddWebStorageScheme(const char* new_scheme); +URL_EXPORT const std::vector<std::string>& GetWebStorageSchemes(); + // Sets a flag to prevent future calls to Add*Scheme from succeeding. // // This is designed to help prevent errors for multithreaded applications.